diff options
author | Matteo Bernardini <ponce@slackbuilds.org> | 2022-02-03 16:01:19 +0100 |
---|---|---|
committer | Willy Sudiarto Raharjo <willysr@slackbuilds.org> | 2022-02-04 17:53:36 +0700 |
commit | fc13eb20fa1980a307d874a069f6b5acb039c546 (patch) | |
tree | 1c86e482cf75ed60d86ffceabbb0fd964db96291 /misc/stardict | |
parent | ba05e0d9dc82fd9e18bd7e87bb9c4c18336a5c07 (diff) |
misc/stardict: Updated for version 3.0.6.2.
Signed-off-by: Matteo Bernardini <ponce@slackbuilds.org>
Signed-off-by: Willy Sudiarto Raharjo <willysr@slackbuilds.org>
Diffstat (limited to 'misc/stardict')
-rw-r--r-- | misc/stardict/patches/fixup_build_on_gcc44.patch | 8728 | ||||
-rw-r--r-- | misc/stardict/patches/stardict-3.0.1-gcc47.patch | 24 | ||||
-rw-r--r-- | misc/stardict/patches/stardict-transparent.patch | 101 | ||||
-rw-r--r-- | misc/stardict/stardict.SlackBuild | 20 | ||||
-rw-r--r-- | misc/stardict/stardict.info | 6 |
5 files changed, 18 insertions, 8861 deletions
diff --git a/misc/stardict/patches/fixup_build_on_gcc44.patch b/misc/stardict/patches/fixup_build_on_gcc44.patch deleted file mode 100644 index 96531719761f..000000000000 --- a/misc/stardict/patches/fixup_build_on_gcc44.patch +++ /dev/null @@ -1,8728 +0,0 @@ -diff -Nur stardict-3.0.1.orig//src/gconf_file.cpp stardict-3.0.1/src/gconf_file.cpp ---- stardict-3.0.1.orig//src/gconf_file.cpp 2007-07-10 02:16:04.000000000 -0500 -+++ stardict-3.0.1/src/gconf_file.cpp 2010-05-24 00:53:36.371667435 -0500 -@@ -22,6 +22,8 @@ - # include "config.h" - #endif - -+#include <memory> -+ - #include <glib/gi18n.h> - - #include "gconf_file.hpp" -diff -Nur stardict-3.0.1.orig//src/gconf_file.cpp~ stardict-3.0.1/src/gconf_file.cpp~ ---- stardict-3.0.1.orig//src/gconf_file.cpp~ 1969-12-31 18:00:00.000000000 -0600 -+++ stardict-3.0.1/src/gconf_file.cpp~ 2007-07-10 02:16:04.000000000 -0500 -@@ -0,0 +1,224 @@ -+/* -+ * This file part of StarDict - A international dictionary for GNOME. -+ * http://stardict.sourceforge.net -+ * Copyright (C) 2005-2006 Evgeniy <dushistov@mail.ru> -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 3 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU Library General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -+ */ -+ -+#ifdef HAVE_CONFIG_H -+# include "config.h" -+#endif -+ -+#include <glib/gi18n.h> -+ -+#include "gconf_file.hpp" -+ -+gconf_file::gconf_file(const std::string& path) -+{ -+ cfgname=path; -+ if ((gconf_client = gconf_client_get_default())==NULL) -+ g_warning("Cannot connect to gconf.\n"); -+ else -+ gconf_client_add_dir(gconf_client, cfgname.c_str(), GCONF_CLIENT_PRELOAD_RECURSIVE, NULL); -+} -+ -+gconf_file::~gconf_file() -+{ -+ for (std::vector<guint>::iterator it=notification_ids.begin(); -+ it!=notification_ids.end(); ++it) -+ gconf_client_notify_remove(gconf_client, *it); -+ -+ if (!gconf_client) -+ return; -+ gconf_client_remove_dir(gconf_client, cfgname.c_str(), NULL); -+ g_object_unref(gconf_client); -+} -+ -+bool gconf_file::read_bool(const gchar *sect, const gchar *key, bool& val) -+{ -+ if (!gconf_client) -+ return false; -+ -+ std::string real_key(std::string(sect)+"/"+key); -+ -+ GConfValue *gval=gconf_client_get(gconf_client, real_key.c_str(), NULL); -+ if (!gval) -+ return false; -+ val=gconf_value_get_bool(gval); -+ gconf_value_free(gval); -+ -+ return true; -+} -+ -+bool gconf_file::read_int(const gchar *sect, const gchar *key, int& val) -+{ -+ if (!gconf_client) -+ return false; -+ std::string real_key(std::string(sect)+"/"+key); -+ GConfValue *gval=gconf_client_get(gconf_client, real_key.c_str(), NULL); -+ if (!gval) -+ return false; -+ val=gconf_value_get_int(gval); -+ gconf_value_free(gval); -+ -+ return true; -+} -+ -+bool gconf_file::read_string(const gchar * sect, const gchar *key, std::string& val) -+{ -+ if (!gconf_client) -+ return false; -+ -+ std::string real_key(std::string(sect)+"/"+key); -+ gchar *gconf_val = gconf_client_get_string(gconf_client, real_key.c_str(), NULL); -+ if (gconf_val!=NULL) -+ val=gconf_val; -+ -+ g_free(gconf_val); -+ -+ return true; -+} -+ -+bool gconf_file::read_strlist(const gchar * sect, const gchar * key, std::list<std::string>& slist) -+{ -+ if (!gconf_client) -+ return false; -+ -+ std::string real_key(std::string(sect)+"/"+key); -+ GSList *gslist = gconf_client_get_list(gconf_client, real_key.c_str(), GCONF_VALUE_STRING, NULL); -+ if (!gslist) -+ return false; -+ -+ slist.clear(); -+ GSList *p = gslist; -+ while (p) { -+ slist.push_back(static_cast<char *>(p->data)); -+ g_free(p->data); -+ p=g_slist_next(p); -+ } -+ g_slist_free(gslist); -+ -+ return true; -+} -+ -+void gconf_file::write_bool(const gchar *sect, const gchar *key, bool val) -+{ -+ if (!gconf_client) -+ return; -+ gchar *real_key=g_strdup_printf("%s/%s", sect, key); -+ gconf_client_set_bool(gconf_client, real_key, val, NULL); -+ g_free(real_key); -+} -+ -+void gconf_file::write_int(const gchar *sect, const gchar *key, int val) -+{ -+ if (!gconf_client) -+ return; -+ gchar *real_key=g_strdup_printf("%s/%s", sect, key); -+ gconf_client_set_int(gconf_client, real_key, val, NULL); -+ g_free(real_key); -+} -+ -+void gconf_file::write_string(const gchar *sect, const gchar *key, const std::string& val) -+{ -+ if(!gconf_client) -+ return; -+ gchar *real_key=g_strdup_printf("%s/%s", sect, key); -+ gconf_client_set_string(gconf_client, real_key, val.c_str(), NULL); -+ g_free(real_key); -+} -+ -+void gconf_file::write_strlist(const gchar *sect, const gchar *key, const std::list<std::string>& slist) -+{ -+ if (!gconf_client) -+ return; -+ -+ GSList *gslist = NULL; -+ for (std::list<std::string>::const_iterator p = slist.begin(); -+ p!=slist.end(); ++p) -+ gslist = g_slist_append(gslist, const_cast<char *>(p->c_str())); -+ -+ gchar *real_key=g_strdup_printf("%s/%s", sect, key); -+ gconf_client_set_list(gconf_client, real_key, GCONF_VALUE_STRING, gslist, NULL); -+ g_free(real_key); -+ g_slist_free(gslist); -+} -+ -+static void gconf_client_notify_func(GConfClient *client, guint cnxn_id, -+ GConfEntry *entry, gpointer user_data) -+{ -+ sigc::signal<void, const baseconfval*> *ch = -+ static_cast< sigc::signal<void, const baseconfval*> *>(user_data); -+ std::auto_ptr<baseconfval> cv; -+ switch (entry->value->type) { -+ case GCONF_VALUE_BOOL: -+ cv.reset(new confval<bool>); -+ static_cast<confval<bool> *>(cv.get())->val_ = -+ gconf_value_get_bool(entry->value); -+ break; -+ case GCONF_VALUE_INT: -+ cv.reset(new confval<int>); -+ static_cast<confval<int> *>(cv.get())->val_ = -+ gconf_value_get_int(entry->value); -+ break; -+ case GCONF_VALUE_STRING: { -+ cv.reset(new confval<std::string>); -+ const gchar *gconf_val = gconf_value_get_string(entry->value); -+ if (gconf_val) -+ static_cast<confval<std::string> *>(cv.get())->val_ = -+ gconf_val; -+ } -+ case GCONF_VALUE_LIST: { -+ confval<std::list<std::string> > *newval = -+ new confval<std::list<std::string> >; -+ cv.reset(newval); -+ GSList *gslist = gconf_value_get_list(entry->value); -+ -+ -+ GSList *p = gslist; -+ while (p) { -+ newval->val_.push_back(static_cast<char *>(p->data)); -+ p = g_slist_next(p); -+ } -+ -+ } -+ break; -+ default: -+ g_assert(false); -+ return; -+ } -+ ch->emit(cv.get()); -+} -+ -+static void gfree_func(gpointer data) -+{ -+ sigc::signal<void, const baseconfval*> *bcv = -+ static_cast< sigc::signal<void, const baseconfval*> *>(data); -+ delete bcv; -+} -+ -+void gconf_file::notify_add(const gchar *sect, const gchar *key, -+ const sigc::slot<void, const baseconfval*>& slot) -+{ -+ std::string name = std::string(sect) + "/" + key; -+ sigc::signal<void, const baseconfval*> *ch = -+ new sigc::signal<void, const baseconfval*>; -+ ch->connect(slot); -+ guint id = gconf_client_notify_add(gconf_client, name.c_str(), -+ gconf_client_notify_func, ch, -+ gfree_func, NULL); -+ notification_ids.push_back(id); -+} -diff -Nur stardict-3.0.1.orig//src/inifile.cpp stardict-3.0.1/src/inifile.cpp ---- stardict-3.0.1.orig//src/inifile.cpp 2007-08-01 04:43:00.000000000 -0500 -+++ stardict-3.0.1/src/inifile.cpp 2010-05-24 00:53:36.372667591 -0500 -@@ -25,6 +25,7 @@ - #include <vector> - #include <cerrno> - #include <cstring> -+#include <cstdlib> - #include <cstdio> - #include <glib/gi18n.h> - #include <glib/gstdio.h> -diff -Nur stardict-3.0.1.orig//src/inifile.cpp~ stardict-3.0.1/src/inifile.cpp~ ---- stardict-3.0.1.orig//src/inifile.cpp~ 1969-12-31 18:00:00.000000000 -0600 -+++ stardict-3.0.1/src/inifile.cpp~ 2007-08-01 04:43:00.000000000 -0500 -@@ -0,0 +1,272 @@ -+/* -+ * This file part of StarDict - A international dictionary for GNOME. -+ * http://stardict.sourceforge.net -+ * Copyright (C) 2005-2006 Evgeniy <dushistov@mail.ru> -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 3 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU Library General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -+ */ -+ -+#ifdef HAVE_CONFIG_H -+# include "config.h" -+#endif -+ -+#include <vector> -+#include <cerrno> -+#include <cstring> -+#include <cstdio> -+#include <glib/gi18n.h> -+#include <glib/gstdio.h> -+ -+#include "utils.h" -+ -+#include "inifile.hpp" -+ -+static const guchar NEW_STRING_SEP = 1; -+static const guchar OLD_STRING_SEP = 0xFF; -+static const gchar *myversion = "1.0"; -+ -+typedef ResourceWrapper<GError, GError, g_error_free> MyGError; -+ -+void inifile::create_empty() -+{ -+ g_key_file_set_string(gkeyfile_, "stardict-private", "version", -+ myversion); -+ save(); -+ g_key_file_free(gkeyfile_); -+} -+ -+void inifile::convert_from_locale_enc() -+{ -+ MyGError err; -+ glib::CharStr data; -+ -+ if (!g_file_get_contents(fname_.c_str(), get_addr(data), NULL, -+ get_addr(err))) { -+ g_error(("Can not read %s, reason %s\n"), fname_.c_str(), -+ err->message); -+ exit(EXIT_SUCCESS); -+ } -+ -+ glib::CharStr utfdata(g_locale_to_utf8(get_impl(data), -1, NULL, NULL, -+ NULL)); -+ if (!utfdata) { -+ g_error(("Can not convert ini file content to current locale\n")); -+ exit(EXIT_SUCCESS); -+ } -+ -+ if (!g_file_set_contents(fname_.c_str(), get_impl(utfdata), -1, get_addr(err))) { -+ g_error("can not save content of ini file %s, reason %s\n", -+ fname_.c_str(), err->message); -+ exit(EXIT_SUCCESS); -+ } -+} -+ -+inifile::inifile(const std::string& path) -+{ -+ fname_ = path; -+ bool done = false; -+ while (!done) { -+ gkeyfile_ = g_key_file_new(); -+ g_key_file_set_list_separator(gkeyfile_, NEW_STRING_SEP); -+/* create file if not exist, because of g_key_file can not do that */ -+ if (!g_file_test(path.c_str(), -+ GFileTest(G_FILE_TEST_EXISTS | -+ G_FILE_TEST_IS_REGULAR))) { -+ create_empty(); -+ continue; -+ } -+ -+ MyGError err; -+ if (!g_key_file_load_from_file(gkeyfile_, path.c_str(), -+ GKeyFileFlags(G_KEY_FILE_KEEP_COMMENTS | -+ G_KEY_FILE_KEEP_TRANSLATIONS), -+ get_addr(err))) { -+ if (err->code == G_KEY_FILE_ERROR_UNKNOWN_ENCODING) { -+ g_key_file_free(gkeyfile_); -+ convert_from_locale_enc(); -+ continue; -+ } -+ g_error(("Can not open config file: %s, reason: %s\n"), -+ path.c_str(), err->message); -+ exit(EXIT_FAILURE);//just in case -+ } -+ -+ glib::CharStr version(g_key_file_get_string(gkeyfile_, "stardict-private", -+ "version", get_addr(err))); -+ if (err) { -+ if (err->code != G_KEY_FILE_ERROR_KEY_NOT_FOUND && -+ err->code != G_KEY_FILE_ERROR_GROUP_NOT_FOUND) { -+ g_error(("internal error, reason: %s\n"), -+ err->message); -+ exit(EXIT_FAILURE);//just in case -+ } -+ create_empty(); -+ continue; -+ } -+ if (strcmp(get_impl(version), myversion)) { -+ g_error(("unsupported ini file format\n")); -+ exit(EXIT_FAILURE); -+ } -+ done = true; -+ } -+ -+} -+ -+void inifile::save() -+{ -+ gsize len; -+ MyGError err; -+ glib::CharStr data( -+ g_key_file_to_data(gkeyfile_, &len, get_addr(err))); -+ -+ if (err) { -+ g_warning(("internal error, reason: %s\n"), -+ err->message); -+ return; -+ } -+ FILE *f = g_fopen(fname_.c_str(), "w"); -+ if (!f) { -+ g_warning(("can not open file: %s\n"), -+ fname_.c_str()); -+ return; -+ } -+ size_t writeb = fwrite(get_impl(data), 1, len, f); -+ fclose(f); -+ if (writeb < len) -+ g_warning(("write to %s failed, instead of %lu," -+ " we wrote %lu\n"), fname_.c_str(), gulong(len), gulong(writeb)); -+} -+ -+inifile::~inifile() -+{ -+ save(); -+ g_key_file_free(gkeyfile_); -+} -+ -+static bool report_error(GError *err, const gchar *sect, const gchar *key) -+{ -+ bool res = false; -+ if (err->code == G_KEY_FILE_ERROR_KEY_NOT_FOUND || -+ err->code == G_KEY_FILE_ERROR_GROUP_NOT_FOUND) -+ res = true; -+ else -+ g_warning("Can not read %s/%s value," -+ " reason %s\n", sect, key, err->message); -+ g_error_free(err); -+ return res; -+} -+ -+bool inifile::read_bool(const gchar *sect, const gchar *key, bool& val) -+{ -+ GError *err = NULL; -+ -+ gboolean newval = g_key_file_get_boolean(gkeyfile_, sect, key, &err); -+ if (err) -+ return report_error(err, sect, key); -+ -+ val = newval; -+ return true; -+} -+ -+bool inifile::read_int(const gchar *sect, const gchar *key, int& val) -+{ -+ GError *err = NULL; -+ gint newval = g_key_file_get_integer(gkeyfile_, sect, key, &err); -+ if (err) -+ return report_error(err, sect, key); -+ -+ val = newval; -+ return true; -+} -+ -+bool inifile::read_string(const gchar * sect, const gchar *key, std::string& val) -+{ -+ GError *err = NULL; -+ gchar *newval = g_key_file_get_string(gkeyfile_, sect, key, &err); -+ if (err) { -+ g_free(newval); -+ return report_error(err, sect, key); -+ } -+ val = newval; -+ g_free(newval); -+ return true; -+} -+ -+bool inifile::read_strlist(const gchar *sect, const gchar * key, -+ std::list<std::string>& slist) -+{ -+ GError *err = NULL; -+ gchar **newval = g_key_file_get_string_list(gkeyfile_, sect, key, -+ NULL, &err); -+ if (err) { -+ g_strfreev(newval); -+ return report_error(err, sect, key); -+ } -+ slist.clear(); -+ gchar **p = newval; -+ while (*p) { -+ slist.push_back(*p); -+ ++p; -+ } -+ g_strfreev(newval); -+ return true; -+} -+ -+void inifile::write_bool(const gchar *sect, const gchar *key, bool val) -+{ -+ g_key_file_set_boolean(gkeyfile_, sect, key, val); -+ expose_event(sect, key, val); -+} -+ -+void inifile::write_int(const gchar *sect, const gchar *key, int val) -+{ -+ g_key_file_set_integer(gkeyfile_, sect, key, val); -+ expose_event(sect, key, val); -+} -+ -+void inifile::write_string(const gchar *sect, const gchar *key, -+ const std::string& val) -+{ -+ g_key_file_set_string(gkeyfile_, sect, key, val.c_str()); -+ expose_event(sect, key, val); -+} -+ -+void inifile::write_strlist(const gchar *sect, const gchar *key, -+ const std::list<std::string>& slist) -+{ -+ size_t len = slist.size(); -+ std::vector<const gchar *> glib_list(len + 1); -+ -+ std::list<std::string>::const_iterator it; -+ size_t i; -+ -+ for (it = slist.begin(), i = 0; it != slist.end(); ++it, ++i) -+ glib_list[i] = it->c_str(); -+ glib_list[i] = NULL; -+ g_key_file_set_string_list(gkeyfile_, sect, key, &glib_list[0], len); -+ expose_event(sect, key, slist); -+} -+ -+void inifile::notify_add(const gchar *sect, const gchar *key, -+ const sigc::slot<void, const baseconfval*>& slot) -+{ -+ std::string name = std::string(sect) + "/" + key; -+ -+ ChangeEventsMap::iterator it = -+ change_events_map_.insert( -+ std::make_pair(name, -+ sigc::signal<void, const baseconfval*>())).first; -+ it->second.connect(slot); -+} -diff -Nur stardict-3.0.1.orig//src/lib/common.cpp stardict-3.0.1/src/lib/common.cpp ---- stardict-3.0.1.orig//src/lib/common.cpp 2007-09-24 21:27:24.000000000 -0500 -+++ stardict-3.0.1/src/lib/common.cpp 2010-05-24 00:53:36.372667591 -0500 -@@ -25,6 +25,8 @@ - #endif - - #include "common.hpp" -+#include <cstring> -+#include <cstdlib> - - static void parse_description(const char *p, long len, std::string &description) - { -diff -Nur stardict-3.0.1.orig//src/lib/common.cpp~ stardict-3.0.1/src/lib/common.cpp~ ---- stardict-3.0.1.orig//src/lib/common.cpp~ 1969-12-31 18:00:00.000000000 -0600 -+++ stardict-3.0.1/src/lib/common.cpp~ 2007-09-24 21:27:24.000000000 -0500 -@@ -0,0 +1,221 @@ -+/* -+ * This file part of StarDict - A international dictionary for GNOME. -+ * http://stardict.sourceforge.net -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 3 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU Library General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -+ */ -+ -+/* -+ * implementation of methods of common for dictionaries structures -+ */ -+#ifdef HAVE_CONFIG_H -+# include "config.h" -+#endif -+ -+#include "common.hpp" -+ -+static void parse_description(const char *p, long len, std::string &description) -+{ -+ description.clear(); -+ const char *p1 = p; -+ while (p1 - p < len) { -+ if (*p1 == '<') { -+ p1++; -+ if ((*p1 == 'b' || *p1 == 'B') && (*(p1+1)=='r' || *(p1+1)=='R') && *(p1+2)=='>') { -+ description += '\n'; -+ p1+=3; -+ } else { -+ description += '<'; -+ } -+ } else { -+ description += *p1; -+ p1++; -+ } -+ } -+} -+ -+//looks not optimal, TODO: refactor -+bool DictInfo::load_from_ifo_file(const std::string& ifofilename, -+ bool istreedict) -+{ -+ ifo_file_name=ifofilename; -+ gchar *buffer; -+ if (!g_file_get_contents(ifofilename.c_str(), &buffer, NULL, NULL)) -+ return false; -+ -+#define TREEDICT_MAGIC_DATA "StarDict's treedict ifo file\nversion=" -+#define DICT_MAGIC_DATA "StarDict's dict ifo file\nversion=" -+ const gchar *magic_data=istreedict ? TREEDICT_MAGIC_DATA : DICT_MAGIC_DATA; -+ if (!g_str_has_prefix(buffer, magic_data)) { -+ g_free(buffer); -+ return false; -+ } -+ -+ bool is_dict_300 = false; -+ gchar *p1; -+ if (istreedict) { -+ p1 = buffer + sizeof(TREEDICT_MAGIC_DATA) -1; -+#define TREEDICT_VERSION_242 "2.4.2\n" -+ if (g_str_has_prefix(p1, TREEDICT_VERSION_242)) { -+ p1 += sizeof(TREEDICT_VERSION_242) -2; -+ } else { -+ g_print("Load %s failed: Unknown version.\n", ifofilename.c_str()); -+ g_free(buffer); -+ return false; -+ } -+ } else { -+ p1 = buffer + sizeof(DICT_MAGIC_DATA) -1; -+#define DICT_VERSION_242 "2.4.2\n" -+#define DICT_VERSION_300 "3.0.0\n" -+ if (g_str_has_prefix(p1, DICT_VERSION_242)) { -+ p1 += sizeof(DICT_VERSION_242) -2; -+ } else if (g_str_has_prefix(p1, DICT_VERSION_300)) { -+ p1 += sizeof(DICT_VERSION_300) -2; -+ is_dict_300 = true; -+ } else { -+ g_print("Load %s failed: Unknown version.\n", ifofilename.c_str()); -+ g_free(buffer); -+ return false; -+ } -+ } -+ -+ gchar *p2,*p3; -+ -+ if (is_dict_300) { -+ p2 = strstr(p1,"\nidxoffsetbits="); -+ if (p2) { -+ p2 = p2 + sizeof("\nidxoffsetbits=") -1; -+ if (g_str_has_prefix(p2, "64\n")) { -+ // TODO -+ g_print("Load %s failed: not supported presently.\n", ifofilename.c_str()); -+ g_free(buffer); -+ return false; -+ } -+ } -+ } -+ -+ p2 = strstr(p1,"\nwordcount="); -+ if (!p2) { -+ g_free(buffer); -+ return false; -+ } -+ -+ p3 = strchr(p2+ sizeof("\nwordcount=")-1,'\n'); -+ gchar *tmpstr = (gchar *)g_memdup(p2+sizeof("\nwordcount=")-1, p3-(p2+sizeof("\nwordcount=")-1)+1); -+ tmpstr[p3-(p2+sizeof("\nwordcount=")-1)] = '\0'; -+ wordcount = atol(tmpstr); -+ g_free(tmpstr); -+ -+ p2 = strstr(p1,"\nsynwordcount="); -+ if (p2) { -+ p3 = strchr(p2+ sizeof("\nsynwordcount=")-1,'\n'); -+ gchar *tmpstr = (gchar *)g_memdup(p2+sizeof("\nsynwordcount=")-1, p3-(p2+sizeof("\nsynwordcount=")-1)+1); -+ tmpstr[p3-(p2+sizeof("\nsynwordcount=")-1)] = '\0'; -+ synwordcount = atol(tmpstr); -+ g_free(tmpstr); -+ } else { -+ synwordcount = 0; -+ } -+ -+ if (istreedict) { -+ p2 = strstr(p1,"\ntdxfilesize="); -+ if (!p2) { -+ g_free(buffer); -+ return false; -+ } -+ p3 = strchr(p2+ sizeof("\ntdxfilesize=")-1,'\n'); -+ tmpstr = (gchar *)g_memdup(p2+sizeof("\ntdxfilesize=")-1, p3-(p2+sizeof("\ntdxfilesize=")-1)+1); -+ tmpstr[p3-(p2+sizeof("\ntdxfilesize=")-1)] = '\0'; -+ index_file_size = atol(tmpstr); -+ g_free(tmpstr); -+ } else { -+ p2 = strstr(p1,"\nidxfilesize="); -+ if (!p2) { -+ g_free(buffer); -+ return false; -+ } -+ -+ p3 = strchr(p2+ sizeof("\nidxfilesize=")-1,'\n'); -+ tmpstr = (gchar *)g_memdup(p2+sizeof("\nidxfilesize=")-1, p3-(p2+sizeof("\nidxfilesize=")-1)+1); -+ tmpstr[p3-(p2+sizeof("\nidxfilesize=")-1)] = '\0'; -+ index_file_size = atol(tmpstr); -+ g_free(tmpstr); -+ -+ p2 = strstr(p1,"\ndicttype="); -+ if (p2) { -+ p2+=sizeof("\ndicttype=")-1; -+ p3 = strchr(p2, '\n'); -+ dicttype.assign(p2, p3-p2); -+ } -+ } -+ -+ p2 = strstr(p1,"\nbookname="); -+ -+ if (!p2) { -+ g_free(buffer); -+ return false; -+ } -+ -+ p2 = p2 + sizeof("\nbookname=") -1; -+ p3 = strchr(p2, '\n'); -+ bookname.assign(p2, p3-p2); -+ -+ p2 = strstr(p1,"\nauthor="); -+ if (p2) { -+ p2 = p2 + sizeof("\nauthor=") -1; -+ p3 = strchr(p2, '\n'); -+ author.assign(p2, p3-p2); -+ } -+ -+ p2 = strstr(p1,"\nemail="); -+ if (p2) { -+ p2 = p2 + sizeof("\nemail=") -1; -+ p3 = strchr(p2, '\n'); -+ email.assign(p2, p3-p2); -+ } -+ -+ p2 = strstr(p1,"\nwebsite="); -+ if (p2) { -+ p2 = p2 + sizeof("\nwebsite=") -1; -+ p3 = strchr(p2, '\n'); -+ website.assign(p2, p3-p2); -+ } -+ -+ p2 = strstr(p1,"\ndate="); -+ if (p2) { -+ p2 = p2 + sizeof("\ndate=") -1; -+ p3 = strchr(p2, '\n'); -+ date.assign(p2, p3-p2); -+ } -+ -+ p2 = strstr(p1,"\ndescription="); -+ if (p2) { -+ p2 = p2 + sizeof("\ndescription=")-1; -+ p3 = strchr(p2, '\n'); -+ parse_description(p2, p3-p2, description); -+ } -+ -+ p2 = strstr(p1,"\nsametypesequence="); -+ if (p2) { -+ p2+=sizeof("\nsametypesequence=")-1; -+ p3 = strchr(p2, '\n'); -+ sametypesequence.assign(p2, p3-p2); -+ } -+ -+ g_free(buffer); -+ -+ return true; -+} -+ -diff -Nur stardict-3.0.1.orig//src/lib/data.cpp stardict-3.0.1/src/lib/data.cpp ---- stardict-3.0.1.orig//src/lib/data.cpp 2007-09-20 20:09:52.000000000 -0500 -+++ stardict-3.0.1/src/lib/data.cpp 2010-05-24 00:54:04.762542528 -0500 -@@ -26,7 +26,8 @@ - - #include "data.hpp" - #include "getuint32.h" -- -+#include <stdio.h> -+#include <cstring> - - DictBase::DictBase() - { -diff -Nur stardict-3.0.1.orig//src/lib/data.cpp~ stardict-3.0.1/src/lib/data.cpp~ ---- stardict-3.0.1.orig//src/lib/data.cpp~ 1969-12-31 18:00:00.000000000 -0600 -+++ stardict-3.0.1/src/lib/data.cpp~ 2007-09-20 20:09:52.000000000 -0500 -@@ -0,0 +1,298 @@ -+/* -+ * This file part of StarDict - A international dictionary for GNOME. -+ * http://stardict.sourceforge.net -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 3 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU Library General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -+ */ -+ -+/* implementation of class to work with dictionary data */ -+#ifdef HAVE_CONFIG_H -+# include "config.h" -+#endif -+ -+#include "kmp.h" -+ -+#include "data.hpp" -+#include "getuint32.h" -+ -+ -+DictBase::DictBase() -+{ -+ dictfile = NULL; -+ cache_cur =0; -+} -+ -+DictBase::~DictBase() -+{ -+ if (dictfile) -+ fclose(dictfile); -+} -+ -+gchar* DictBase::GetWordData(guint32 idxitem_offset, guint32 idxitem_size) -+{ -+ for (int i=0; i<WORDDATA_CACHE_NUM; i++) -+ if (cache[i].data && cache[i].offset == idxitem_offset) -+ return cache[i].data; -+ -+ if (dictfile) -+ fseek(dictfile, idxitem_offset, SEEK_SET); -+ -+ gchar *data; -+ if (!sametypesequence.empty()) { -+ gchar *origin_data = (gchar *)g_malloc(idxitem_size); -+ -+ if (dictfile) -+ fread(origin_data, idxitem_size, 1, dictfile); -+ else -+ dictdzfile->read(origin_data, idxitem_offset, idxitem_size); -+ -+ guint32 data_size; -+ gint sametypesequence_len = sametypesequence.length(); -+ //there have sametypesequence_len char being omitted. -+ data_size = idxitem_size + sametypesequence_len; //Here is a bug fix of 2.4.8, which don't add sizeof(guint32) anymore. -+ -+ //if the last item's size is determined by the end up '\0',then +=sizeof(gchar); -+ //if the last item's size is determined by the head guint32 type data,then +=sizeof(guint32); -+ switch (sametypesequence[sametypesequence_len-1]) { -+ case 'm': -+ case 't': -+ case 'y': -+ case 'l': -+ case 'g': -+ case 'x': -+ case 'k': -+ case 'w': -+ data_size += sizeof(gchar); -+ break; -+ case 'W': -+ case 'P': -+ data_size += sizeof(guint32); -+ break; -+ default: -+ if (g_ascii_isupper(sametypesequence[sametypesequence_len-1])) -+ data_size += sizeof(guint32); -+ else -+ data_size += sizeof(gchar); -+ break; -+ } -+ data = (gchar *)g_malloc(data_size + sizeof(guint32)); -+ gchar *p1,*p2; -+ p1 = data + sizeof(guint32); -+ p2 = origin_data; -+ guint32 sec_size; -+ //copy the head items. -+ for (int i=0; i<sametypesequence_len-1; i++) { -+ *p1=sametypesequence[i]; -+ p1+=sizeof(gchar); -+ switch (sametypesequence[i]) { -+ case 'm': -+ case 't': -+ case 'y': -+ case 'l': -+ case 'g': -+ case 'x': -+ case 'k': -+ case 'w': -+ sec_size = strlen(p2)+1; -+ memcpy(p1, p2, sec_size); -+ p1+=sec_size; -+ p2+=sec_size; -+ break; -+ case 'W': -+ case 'P': -+ sec_size = get_uint32(p2); -+ sec_size += sizeof(guint32); -+ memcpy(p1, p2, sec_size); -+ p1+=sec_size; -+ p2+=sec_size; -+ break; -+ default: -+ if (g_ascii_isupper(sametypesequence[i])) { -+ sec_size = get_uint32(p2); -+ sec_size += sizeof(guint32); -+ } else { -+ sec_size = strlen(p2)+1; -+ } -+ memcpy(p1, p2, sec_size); -+ p1+=sec_size; -+ p2+=sec_size; -+ break; -+ } -+ } -+ //calculate the last item 's size. -+ sec_size = idxitem_size - (p2-origin_data); -+ *p1=sametypesequence[sametypesequence_len-1]; -+ p1+=sizeof(gchar); -+ switch (sametypesequence[sametypesequence_len-1]) { -+ case 'm': -+ case 't': -+ case 'y': -+ case 'l': -+ case 'g': -+ case 'x': -+ case 'k': -+ case 'w': -+ memcpy(p1, p2, sec_size); -+ p1 += sec_size; -+ *p1='\0';//add the end up '\0'; -+ break; -+ case 'W': -+ case 'P': -+ memcpy(p1, &sec_size, sizeof(guint32)); -+ p1 += sizeof(guint32); -+ memcpy(p1, p2, sec_size); -+ break; -+ default: -+ if (g_ascii_isupper(sametypesequence[sametypesequence_len-1])) { -+ memcpy(p1, &sec_size, sizeof(guint32)); -+ p1 += sizeof(guint32); -+ memcpy(p1, p2, sec_size); -+ } else { -+ memcpy(p1, p2, sec_size); -+ p1 += sec_size; -+ *p1='\0'; -+ } -+ break; -+ } -+ g_free(origin_data); -+ memcpy(data, &data_size, sizeof(guint32)); -+ } else { -+ data = (gchar *)g_malloc(idxitem_size + sizeof(guint32)); -+ if (dictfile) -+ fread(data+sizeof(guint32), idxitem_size, 1, dictfile); -+ else -+ dictdzfile->read(data+sizeof(guint32), idxitem_offset, idxitem_size); -+ memcpy(data, &idxitem_size, sizeof(guint32)); -+ } -+ g_free(cache[cache_cur].data); -+ -+ cache[cache_cur].data = data; -+ cache[cache_cur].offset = idxitem_offset; -+ cache_cur++; -+ if (cache_cur==WORDDATA_CACHE_NUM) -+ cache_cur = 0; -+ return data; -+} -+ -+bool DictBase::SearchData(std::vector<std::string> &SearchWords, guint32 idxitem_offset, guint32 idxitem_size, gchar *origin_data) -+{ -+ int nWord = SearchWords.size(); -+ std::vector<bool> WordFind(nWord, false); -+ int nfound=0; -+ -+ if (dictfile) -+ fseek(dictfile, idxitem_offset, SEEK_SET); -+ if (dictfile) -+ fread(origin_data, idxitem_size, 1, dictfile); -+ else -+ dictdzfile->read(origin_data, idxitem_offset, idxitem_size); -+ gchar *p = origin_data; -+ guint32 sec_size; -+ int j; -+ if (!sametypesequence.empty()) { -+ gint sametypesequence_len = sametypesequence.length(); -+ for (int i=0; i<sametypesequence_len-1; i++) { -+ switch (sametypesequence[i]) { -+ case 'm': -+ case 't': -+ case 'y': -+ case 'l': -+ case 'g': -+ case 'x': -+ case 'k': -+ case 'w': -+ case 'h': -+ for (j=0; j<nWord; j++) -+ // KMP() is faster than strstr() in theory. Really? Always be true? -+ //if (!WordFind[j] && strstr(p, SearchWords[j].c_str())) { -+ if (!WordFind[j] && KMP(p, strlen(p), SearchWords[j].c_str())!=-1) { -+ WordFind[j] = true; -+ ++nfound; -+ } -+ -+ if (nfound==nWord) -+ return true; -+ sec_size = strlen(p)+1; -+ p+=sec_size; -+ break; -+ default: -+ if (g_ascii_isupper(sametypesequence[i])) { -+ sec_size = get_uint32(p); -+ sec_size += sizeof(guint32); -+ } else { -+ sec_size = strlen(p)+1; -+ } -+ p+=sec_size; -+ } -+ } -+ switch (sametypesequence[sametypesequence_len-1]) { -+ case 'm': -+ case 't': -+ case 'y': -+ case 'l': -+ case 'g': -+ case 'x': -+ case 'k': -+ case 'w': -+ case 'h': -+ sec_size = idxitem_size - (p-origin_data); -+ for (j=0; j<nWord; j++) -+ //if (!WordFind[j] && g_strstr_len(p, sec_size, SearchWords[j].c_str())) { -+ if (!WordFind[j] && KMP(p, sec_size, SearchWords[j].c_str())!=-1) { -+ WordFind[j] = true; -+ ++nfound; -+ } -+ -+ if (nfound==nWord) -+ return true; -+ break; -+ } -+ } else { -+ while (guint32(p - origin_data)<idxitem_size) { -+ switch (*p) { -+ case 'm': -+ case 't': -+ case 'y': -+ case 'l': -+ case 'g': -+ case 'x': -+ case 'k': -+ case 'w': -+ case 'h': -+ for (j=0; j<nWord; j++) -+ if (!WordFind[j] && strstr(p, SearchWords[j].c_str())) { -+ WordFind[j] = true; -+ ++nfound; -+ } -+ -+ if (nfound==nWord) -+ return true; -+ sec_size = strlen(p)+1; -+ p+=sec_size; -+ break; -+ default: -+ if (g_ascii_isupper(*p)) { -+ sec_size = get_uint32(p); -+ sec_size += sizeof(guint32); -+ } else { -+ sec_size = strlen(p)+1; -+ } -+ p+=sec_size; -+ } -+ } -+ } -+ return false; -+} -+ -diff -Nur stardict-3.0.1.orig//src/lib/http_client.h stardict-3.0.1/src/lib/http_client.h ---- stardict-3.0.1.orig//src/lib/http_client.h 2007-08-30 04:23:32.000000000 -0500 -+++ stardict-3.0.1/src/lib/http_client.h 2010-05-24 00:53:36.373667747 -0500 -@@ -5,6 +5,7 @@ - #include "sigc++/sigc++.h" - #include <string> - #include <vector> -+#include <cstring> - - #ifndef _WIN32 - # include <netdb.h> -diff -Nur stardict-3.0.1.orig//src/lib/pluginmanager.cpp stardict-3.0.1/src/lib/pluginmanager.cpp ---- stardict-3.0.1.orig//src/lib/pluginmanager.cpp 2007-10-09 22:26:45.000000000 -0500 -+++ stardict-3.0.1/src/lib/pluginmanager.cpp 2010-05-24 00:53:36.374667481 -0500 -@@ -1,6 +1,7 @@ - #include "pluginmanager.h" - #include "file.hpp" - #include <string> -+#include <cstring> - - StarDictPluginBaseObject::StarDictPluginBaseObject(const char *filename, GModule *module_, plugin_configure_func_t configure_func_): - plugin_filename(filename), module(module_), configure_func(configure_func_) -diff -Nur stardict-3.0.1.orig//src/lib/stardict_client.cpp stardict-3.0.1/src/lib/stardict_client.cpp ---- stardict-3.0.1.orig//src/lib/stardict_client.cpp 2007-10-31 03:32:11.000000000 -0500 -+++ stardict-3.0.1/src/lib/stardict_client.cpp 2010-05-24 00:55:03.618667273 -0500 -@@ -30,6 +30,9 @@ - #include "getuint32.h" - - #include "stardict_client.hpp" -+#include <stdio.h> -+#include <cstdlib> -+#include <cstring> - - #define PROTOCOL_VERSION "0.3" - -diff -Nur stardict-3.0.1.orig//src/lib/stardict_client.cpp~ stardict-3.0.1/src/lib/stardict_client.cpp~ ---- stardict-3.0.1.orig//src/lib/stardict_client.cpp~ 1969-12-31 18:00:00.000000000 -0600 -+++ stardict-3.0.1/src/lib/stardict_client.cpp~ 2007-10-31 03:32:11.000000000 -0500 -@@ -0,0 +1,1263 @@ -+/* -+ * This file part of StarDict - A international dictionary for GNOME. -+ * http://stardict.sourceforge.net -+ * Copyright (C) 2006 Hu Zheng <huzheng_001@163.com> -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 3 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU Library General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -+ */ -+ -+#ifdef HAVE_CONFIG_H -+# include "config.h" -+#endif -+ -+#include <glib.h> -+#include <glib/gi18n.h> -+ -+#include "sockets.hpp" -+#include "md5.h" -+#include "getuint32.h" -+ -+#include "stardict_client.hpp" -+ -+#define PROTOCOL_VERSION "0.3" -+ -+#define CODE_HELLO 220 /* text msg-id */ -+#define CODE_GOODBYE 221 /* Closing Connection */ -+#define CODE_OK 250 /* ok */ -+#define CODE_TEMPORARILY_UNAVAILABLE 420 /* server unavailable */ -+#define CODE_SYNTAX_ERROR 500 /* syntax, command not recognized */ -+#define CODE_DENIED 521 -+#define CODE_DICTMASK_NOTSET 522 -+ -+unsigned int STARDICT::Cmd::next_seq = 1; -+ -+sigc::signal<void, const char *> StarDictClient::on_error_; -+sigc::signal<void, const struct STARDICT::LookupResponse *, unsigned int> StarDictClient::on_lookup_end_; -+sigc::signal<void, const struct STARDICT::LookupResponse *, unsigned int> StarDictClient::on_floatwin_lookup_end_; -+sigc::signal<void, const char *> StarDictClient::on_register_end_; -+sigc::signal<void, const char *> StarDictClient::on_getdictmask_end_; -+sigc::signal<void, const char *> StarDictClient::on_dirinfo_end_; -+sigc::signal<void, const char *> StarDictClient::on_dictinfo_end_; -+sigc::signal<void, int> StarDictClient::on_maxdictcount_end_; -+sigc::signal<void, std::list<char *> *> StarDictClient::on_previous_end_; -+sigc::signal<void, std::list<char *> *> StarDictClient::on_next_end_; -+ -+static void arg_escape(std::string &earg, const char *arg) -+{ -+ earg.clear(); -+ while (*arg) { -+ if (*arg=='\\') { -+ earg+="\\\\"; -+ } else if (*arg==' ') { -+ earg+="\\ "; -+ } else if (*arg=='\n') { -+ earg+="\\n"; -+ } else { -+ earg+=*arg; -+ } -+ arg++; -+ } -+} -+ -+STARDICT::Cmd::Cmd(int cmd, ...) -+{ -+ this->seq = this->next_seq; -+ this->next_seq++; -+ this->reading_status = 0; -+ this->command = cmd; -+ va_list ap; -+ va_start( ap, cmd ); -+ switch (cmd) { -+ case CMD_CLIENT: -+ { -+ const char *client_name = va_arg( ap, const char * ); -+ std::string earg1, earg2; -+ arg_escape(earg1, PROTOCOL_VERSION); -+ arg_escape(earg2, client_name); -+ this->data = g_strdup_printf("client %s %s\n", earg1.c_str(), earg2.c_str()); -+ break; -+ } -+ case CMD_REGISTER: -+ { -+ const char *user = va_arg( ap, const char * ); -+ const char *passwd = va_arg( ap, const char * ); -+ const char *email = va_arg( ap, const char * ); -+ std::string earg1, earg2, earg3; -+ arg_escape(earg1, user); -+ arg_escape(earg2, passwd); -+ arg_escape(earg3, email); -+ this->data = g_strdup_printf("register %s %s %s\n", earg1.c_str(), earg2.c_str(), earg3.c_str()); -+ break; -+ } -+ /*case CMD_CHANGE_PASSWD: -+ { -+ const char *user = va_arg( ap, const char * ); -+ const char *old_passwd = va_arg( ap, const char * ); -+ const char *new_passwd = va_arg( ap, const char * ); -+ std::string earg1, earg2, earg3; -+ arg_escape(earg1, user); -+ arg_escape(earg2, old_passwd); -+ arg_escape(earg3, new_passwd); -+ this->data = g_strdup_printf("change_password %s %s %s\n", earg1.c_str(), earg2.c_str(), earg3.c_str()); -+ break; -+ }*/ -+ case CMD_AUTH: -+ this->auth = new AuthInfo(); -+ this->auth->user = va_arg( ap, const char * ); -+ this->auth->passwd = va_arg( ap, const char * ); -+ break; -+ case CMD_LOOKUP: -+ { -+ std::string earg; -+ arg_escape(earg, va_arg( ap, const char * )); -+ this->data = g_strdup_printf("lookup %s 30\n", earg.c_str()); -+ this->lookup_response = NULL; -+ break; -+ } -+ case CMD_PREVIOUS: -+ { -+ std::string earg; -+ arg_escape(earg, va_arg( ap, const char * )); -+ this->data = g_strdup_printf("previous %s 15\n", earg.c_str()); -+ this->wordlist_response = NULL; -+ break; -+ } -+ case CMD_NEXT: -+ { -+ std::string earg; -+ arg_escape(earg, va_arg( ap, const char * )); -+ this->data = g_strdup_printf("next %s 30\n", earg.c_str()); -+ this->wordlist_response = NULL; -+ break; -+ } -+ /*case CMD_QUERY: -+ { -+ std::string earg; -+ arg_escape(earg, va_arg( ap, const char * )); -+ this->data = g_strdup_printf("query %s\n", earg.c_str()); -+ this->lookup_response = NULL; -+ break; -+ }*/ -+ case CMD_SELECT_QUERY: -+ { -+ std::string earg; -+ arg_escape(earg, va_arg( ap, const char * )); -+ this->data = g_strdup_printf("selectquery %s\n", earg.c_str()); -+ this->lookup_response = NULL; -+ break; -+ } -+ case CMD_SMART_QUERY: -+ { -+ std::string earg; -+ arg_escape(earg, va_arg( ap, const char * )); -+ int BeginPos = va_arg( ap, int ); -+ this->data = g_strdup_printf("smartquery %s %d\n", earg.c_str(), BeginPos); -+ this->lookup_response = NULL; -+ break; -+ } -+ case CMD_DEFINE: -+ { -+ std::string earg; -+ arg_escape(earg, va_arg( ap, const char * )); -+ this->data = g_strdup_printf("define %s\n", earg.c_str()); -+ this->lookup_response = NULL; -+ break; -+ } -+ case CMD_SET_DICT_MASK: -+ { -+ std::string earg; -+ arg_escape(earg, va_arg( ap, const char * )); -+ this->data = g_strdup_printf("setdictmask %s\n", earg.c_str()); -+ break; -+ } -+ case CMD_GET_DICT_MASK: -+ this->data = g_strdup("getdictmask\n"); -+ break; -+ /*case CMD_SET_COLLATE_FUNC: -+ { -+ std::string earg; -+ arg_escape(earg, va_arg( ap, const char * )); -+ this->data = g_strdup_printf("setcollatefunc %s\n", earg.c_str()); -+ break; -+ } -+ case CMD_GET_COLLATE_FUNC: -+ this->data = g_strdup("getcollatefunc\n"); -+ break; -+ case CMD_SET_LANGUAGE: -+ { -+ std::string earg; -+ arg_escape(earg, va_arg( ap, const char * )); -+ this->data = g_strdup_printf("setlanguage %s\n", earg.c_str()); -+ break; -+ } -+ case CMD_GET_LANGUAGE: -+ this->data = g_strdup("getlanguage\n"); -+ break; -+ case CMD_SET_EMAIL: -+ { -+ std::string earg; -+ arg_escape(earg, va_arg( ap, const char * )); -+ this->data = g_strdup_printf("setemail %s\n", earg.c_str()); -+ break; -+ } -+ case CMD_GET_EMAIL: -+ this->data = g_strdup("getemail\n"); -+ break; -+ case CMD_GET_USER_LEVEL: -+ this->data = g_strdup("getuserlevel\n"); -+ break;*/ -+ case CMD_MAX_DICT_COUNT: -+ this->data = g_strdup("maxdictcount\n"); -+ break; -+ case CMD_DIR_INFO: -+ { -+ std::string earg; -+ arg_escape(earg, va_arg( ap, const char * )); -+ this->data = g_strdup_printf("dirinfo %s\n", earg.c_str()); -+ break; -+ } -+ case CMD_DICT_INFO: -+ { -+ std::string earg; -+ arg_escape(earg, va_arg( ap, const char * )); -+ this->data = g_strdup_printf("dictinfo %s\n", earg.c_str()); -+ break; -+ } -+ /*case CMD_USER_LEVEL: -+ { -+ std::string earg1, earg2, earg3; -+ arg_escape(earg1, va_arg( ap, const char * )); -+ arg_escape(earg2, va_arg( ap, const char * )); -+ arg_escape(earg3, va_arg( ap, const char * )); -+ this->data = g_strdup_printf("userlevel %s %s %s\n", earg1.c_str(), earg2.c_str(), earg3.c_str()); -+ break; -+ }*/ -+ case CMD_QUIT: -+ this->data = g_strdup("quit\n"); -+ break; -+ } -+ va_end( ap ); -+} -+ -+STARDICT::LookupResponse::DictResponse::DictResponse() -+{ -+ oword = NULL; -+} -+ -+STARDICT::LookupResponse::DictResponse::~DictResponse() -+{ -+ g_free(oword); -+ for (std::list<DictResult *>::iterator i = dict_result_list.begin(); i != dict_result_list.end(); ++i) { -+ delete *i; -+ } -+} -+ -+STARDICT::LookupResponse::DictResponse::DictResult::DictResult() -+{ -+ bookname = NULL; -+} -+ -+STARDICT::LookupResponse::DictResponse::DictResult::~DictResult() -+{ -+ g_free(bookname); -+ for (std::list<WordResult *>::iterator i = word_result_list.begin(); i != word_result_list.end(); ++i) { -+ delete *i; -+ } -+} -+ -+STARDICT::LookupResponse::DictResponse::DictResult::WordResult::WordResult() -+{ -+ word = NULL; -+} -+ -+STARDICT::LookupResponse::DictResponse::DictResult::WordResult::~WordResult() -+{ -+ g_free(word); -+ for (std::list<char *>::iterator i = datalist.begin(); i != datalist.end(); ++i) { -+ g_free(*i); -+ } -+} -+ -+STARDICT::LookupResponse::~LookupResponse() -+{ -+ if (listtype == ListType_List) { -+ for (std::list<char *>::iterator i = wordlist->begin(); i != wordlist->end(); ++i) { -+ g_free(*i); -+ } -+ delete wordlist; -+ } else if (listtype == ListType_Tree) { -+ for (std::list<WordTreeElement *>::iterator i = wordtree->begin(); i != wordtree->end(); ++i) { -+ g_free((*i)->bookname); -+ for (std::list<char *>::iterator j = (*i)->wordlist.begin(); j != (*i)->wordlist.end(); ++j) { -+ g_free(*j); -+ } -+ delete *i; -+ } -+ delete wordtree; -+ } -+} -+ -+STARDICT::Cmd::~Cmd() -+{ -+ if (this->command == CMD_AUTH) { -+ delete this->auth; -+ } else { -+ g_free(this->data); -+ } -+ if (this->command == CMD_LOOKUP || this->command == CMD_DEFINE || this->command == CMD_SELECT_QUERY || this->command == CMD_SMART_QUERY) { -+ delete this->lookup_response; -+ } else if (this->command == CMD_PREVIOUS || this->command == CMD_NEXT) { -+ if (this->wordlist_response) { -+ for (std::list<char *>::iterator i = this->wordlist_response->begin(); i != this->wordlist_response->end(); ++i) { -+ g_free(*i); -+ } -+ delete this->wordlist_response; -+ } -+ } -+} -+ -+StarDictCache::StarDictCache() -+{ -+ str_pool.resize(str_pool_size); -+ for (size_t i = 0; i< str_pool_size; i++) { -+ str_pool[i] = NULL; -+ } -+ cur_str_pool_pos = 0; -+ -+ lookup_response_pool.resize(lookup_response_pool_size); -+ for (size_t i = 0; i< lookup_response_pool_size; i++) { -+ lookup_response_pool[i] = NULL; -+ } -+ cur_lookup_response_pool_pos = 0; -+} -+ -+StarDictCache::~StarDictCache() -+{ -+ clean_all_cache(); -+} -+ -+void StarDictCache::clean_all_cache() -+{ -+ for (std::vector<StrElement *>::iterator i = str_pool.begin(); i != str_pool.end(); ++i) { -+ if (*i) { -+ g_free((*i)->data); -+ delete *i; -+ *i = NULL; -+ } -+ } -+ clean_cache_lookup_response(); -+} -+ -+void StarDictCache::clean_cache_lookup_response() -+{ -+ for (std::vector<LookupResponseElement *>::iterator i = lookup_response_pool.begin(); i != lookup_response_pool.end(); ++i) { -+ if (*i) { -+ delete ((*i)->lookup_response); -+ delete *i; -+ *i = NULL; -+ } -+ } -+} -+ -+char *StarDictCache::get_cache_str(const char *key_str) -+{ -+ for (std::vector<StrElement *>::iterator i = str_pool.begin(); i != str_pool.end(); ++i) { -+ if (*i) { -+ if ((*i)->key == key_str) -+ return (*i)->data; -+ } -+ } -+ return NULL; -+} -+ -+STARDICT::LookupResponse *StarDictCache::get_cache_lookup_response(const char *key_str) -+{ -+ for (std::vector<LookupResponseElement *>::iterator i = lookup_response_pool.begin(); i != lookup_response_pool.end(); ++i) { -+ if (*i) { -+ if ((*i)->key == key_str) -+ return (*i)->lookup_response; -+ } -+ } -+ return NULL; -+} -+ -+void StarDictCache::clean_cache_str(const char *key_str) -+{ -+ for (std::vector<StrElement *>::iterator i = str_pool.begin(); i != str_pool.end(); ++i) { -+ if (*i) { -+ if ((*i)->key == key_str) { -+ g_free((*i)->data); -+ delete *i; -+ *i = NULL; -+ //return; -+ } -+ } -+ } -+} -+ -+void StarDictCache::save_cache_str(const char *key_str, char *data) -+{ -+ if (str_pool[cur_str_pool_pos]) { -+ g_free(str_pool[cur_str_pool_pos]->data); -+ delete str_pool[cur_str_pool_pos]; -+ } -+ str_pool[cur_str_pool_pos] = new StrElement(); -+ str_pool[cur_str_pool_pos]->key = key_str; -+ str_pool[cur_str_pool_pos]->data = data; -+ cur_str_pool_pos++; -+ if (cur_str_pool_pos == str_pool_size) -+ cur_str_pool_pos = 0; -+} -+ -+void StarDictCache::save_cache_lookup_response(const char *key_str, STARDICT::LookupResponse *lookup_response) -+{ -+ if (lookup_response_pool[cur_lookup_response_pool_pos]) { -+ delete lookup_response_pool[cur_lookup_response_pool_pos]->lookup_response; -+ delete lookup_response_pool[cur_lookup_response_pool_pos]; -+ } -+ lookup_response_pool[cur_lookup_response_pool_pos] = new LookupResponseElement(); -+ lookup_response_pool[cur_lookup_response_pool_pos]->key = key_str; -+ lookup_response_pool[cur_lookup_response_pool_pos]->lookup_response = lookup_response; -+ cur_lookup_response_pool_pos++; -+ if (cur_lookup_response_pool_pos == lookup_response_pool_size) -+ cur_lookup_response_pool_pos = 0; -+} -+ -+StarDictClient::StarDictClient() -+{ -+ sd_ = -1; -+ channel_ = NULL; -+ in_source_id_ = 0; -+ out_source_id_ = 0; -+ is_connected_ = false; -+} -+ -+StarDictClient::~StarDictClient() -+{ -+ disconnect(); -+} -+ -+void StarDictClient::set_server(const char *host, int port) -+{ -+ if (host_ != host || port_ != port) { -+ host_ = host; -+ port_ = port; -+ host_resolved = false; -+ clean_all_cache(); -+ } -+} -+ -+void StarDictClient::set_auth(const char *user, const char *md5passwd) -+{ -+ if (user_ != user || md5passwd_ != md5passwd) { -+ user_ = user; -+ md5passwd_ = md5passwd; -+ clean_all_cache(); -+ } -+} -+ -+bool StarDictClient::try_cache(STARDICT::Cmd *c) -+{ -+ if (c->command == STARDICT::CMD_LOOKUP || c->command == STARDICT::CMD_DEFINE || c->command == STARDICT::CMD_SELECT_QUERY || c->command == STARDICT::CMD_SMART_QUERY) { -+ STARDICT::LookupResponse *res = get_cache_lookup_response(c->data); -+ if (res) { -+ if (c->command == STARDICT::CMD_LOOKUP || c->command == STARDICT::CMD_DEFINE) -+ on_lookup_end_.emit(res, 0); -+ else if (c->command == STARDICT::CMD_SELECT_QUERY || c->command == STARDICT::CMD_SMART_QUERY) -+ on_floatwin_lookup_end_.emit(res, 0); -+ delete c; -+ return true; -+ } else { -+ return false; -+ } -+ } -+ if (c->command == STARDICT::CMD_PREVIOUS || c->command == STARDICT::CMD_NEXT) { -+ // Not implemented yet. -+ return false; -+ } -+ char *data = get_cache_str(c->data); -+ if (data) { -+ switch (c->command) { -+ case STARDICT::CMD_DIR_INFO: -+ on_dirinfo_end_.emit(data); -+ break; -+ case STARDICT::CMD_DICT_INFO: -+ on_dictinfo_end_.emit(data); -+ break; -+ case STARDICT::CMD_GET_DICT_MASK: -+ on_getdictmask_end_.emit(data); -+ break; -+ case STARDICT::CMD_MAX_DICT_COUNT: -+ on_maxdictcount_end_.emit(atoi(data)); -+ break; -+ } -+ delete c; -+ return true; -+ } else { -+ return false; -+ } -+} -+ -+void StarDictClient::send_commands(int num, ...) -+{ -+ STARDICT::Cmd *c; -+ if (!is_connected_) { -+#ifdef _WIN32 -+ c = new STARDICT::Cmd(STARDICT::CMD_CLIENT, "StarDict Windows"); -+#else -+ c = new STARDICT::Cmd(STARDICT::CMD_CLIENT, "StarDict Linux"); -+#endif -+ cmdlist.push_back(c); -+ if (!user_.empty() && !md5passwd_.empty()) { -+ c = new STARDICT::Cmd(STARDICT::CMD_AUTH, user_.c_str(), md5passwd_.c_str()); -+ cmdlist.push_back(c); -+ } -+ } -+ va_list ap; -+ va_start( ap, num); -+ for (int i = 0; i< num; i++) { -+ c = va_arg( ap, STARDICT::Cmd *); -+ cmdlist.push_back(c); -+ } -+ va_end( ap ); -+ if (!is_connected_) { -+ waiting_banner_ = true; -+ connect(); -+ } -+} -+ -+void StarDictClient::try_cache_or_send_commands(int num, ...) -+{ -+ STARDICT::Cmd *c; -+ std::list<STARDICT::Cmd *> send_cmdlist; -+ va_list ap; -+ va_start( ap, num); -+ for (int i = 0; i< num; i++) { -+ c = va_arg( ap, STARDICT::Cmd *); -+ if (!try_cache(c)) { -+ send_cmdlist.push_back(c); -+ } -+ } -+ va_end( ap ); -+ if (send_cmdlist.empty()) -+ return; -+ -+ if (!is_connected_) { -+#ifdef _WIN32 -+ c = new STARDICT::Cmd(STARDICT::CMD_CLIENT, "StarDict Windows"); -+#else -+ c = new STARDICT::Cmd(STARDICT::CMD_CLIENT, "StarDict Linux"); -+#endif -+ cmdlist.push_back(c); -+ if (!user_.empty() && !md5passwd_.empty()) { -+ c = new STARDICT::Cmd(STARDICT::CMD_AUTH, user_.c_str(), md5passwd_.c_str()); -+ cmdlist.push_back(c); -+ } -+ } -+ for (std::list<STARDICT::Cmd *>::iterator i = send_cmdlist.begin(); i!= send_cmdlist.end(); ++i) { -+ cmdlist.push_back(*i); -+ } -+ if (!is_connected_) { -+ waiting_banner_ = true; -+ connect(); -+ } -+} -+ -+void StarDictClient::write_str(const char *str, GError **err) -+{ -+ int len = strlen(str); -+ int left_byte = len; -+ GIOStatus res; -+ gsize bytes_written; -+ while (left_byte) { -+ res = g_io_channel_write_chars(channel_, str+(len - left_byte), left_byte, &bytes_written, err); -+ if (res == G_IO_STATUS_ERROR) { -+ disconnect(); -+ return; -+ } -+ left_byte -= bytes_written; -+ } -+ res = g_io_channel_flush(channel_, err); -+ if (res == G_IO_STATUS_ERROR) { -+ disconnect(); -+ } -+ if (out_source_id_ == 0) -+ out_source_id_ = g_io_add_watch(channel_, GIOCondition(G_IO_OUT), on_io_out_event, this); -+} -+ -+void StarDictClient::request_command() -+{ -+ reading_type_ = READ_LINE; -+ if (cmdlist.empty()) { -+ cmdlist.push_back(new STARDICT::Cmd(STARDICT::CMD_QUIT)); -+ } -+ STARDICT::Cmd *c = cmdlist.front(); -+ switch (c->command) { -+ case STARDICT::CMD_AUTH: -+ { -+ struct MD5Context ctx; -+ unsigned char digest[16]; -+ char hex[33]; -+ int i; -+ MD5Init(&ctx); -+ MD5Update(&ctx, (const unsigned char*)cmd_reply.daemonStamp.c_str(), cmd_reply.daemonStamp.length()); -+ MD5Update(&ctx, (const unsigned char*)(c->auth->passwd.c_str()), c->auth->passwd.length()); -+ MD5Final(digest, &ctx ); -+ for (i = 0; i < 16; i++) -+ sprintf( hex+2*i, "%02x", digest[i] ); -+ hex[32] = '\0'; -+ std::string earg1, earg2; -+ arg_escape(earg1, c->auth->user.c_str()); -+ arg_escape(earg2, hex); -+ char *data = g_strdup_printf("auth %s %s\n", earg1.c_str(), earg2.c_str()); -+ GError *err = NULL; -+ write_str(data, &err); -+ g_free(data); -+ if (err) { -+ on_error_.emit(err->message); -+ g_error_free(err); -+ return; -+ } -+ break; -+ } -+ default: -+ { -+ GError *err = NULL; -+ write_str(c->data, &err); -+ if (err) { -+ on_error_.emit(err->message); -+ g_error_free(err); -+ return; -+ } -+ break; -+ } -+ } -+ return; -+} -+ -+void StarDictClient::clean_command() -+{ -+ for (std::list<STARDICT::Cmd *>::iterator i=cmdlist.begin(); i!=cmdlist.end(); ++i) { -+ delete *i; -+ } -+ cmdlist.clear(); -+} -+ -+void StarDictClient::connect() -+{ -+ if (host_resolved) { -+ on_resolved(this, true, sa); -+ } else { -+ Socket::resolve(host_, this, on_resolved); -+ } -+} -+ -+void StarDictClient::on_resolved(gpointer data, bool resolved, in_addr_t sa_) -+{ -+ StarDictClient *oStarDictClient = (StarDictClient *)data; -+ if (!resolved) { -+ static bool showed_once = false; -+ if (!showed_once) { -+ showed_once = true; -+ gchar *mes = g_strdup_printf("Can not reslove %s: %s\n", -+ oStarDictClient->host_.c_str(), Socket::get_error_msg().c_str()); -+ on_error_.emit(mes); -+ g_free(mes); -+ } -+ return; -+ } -+ -+ if (oStarDictClient->host_resolved == false) { -+ oStarDictClient->sa = sa_; -+ oStarDictClient->host_resolved = true; -+ } -+ -+ oStarDictClient->sd_ = Socket::socket(); -+ -+ if (oStarDictClient->sd_ == -1) { -+ std::string str = "Can not create socket: " + Socket::get_error_msg(); -+ on_error_.emit(str.c_str()); -+ return; -+ } -+ Socket::connect(oStarDictClient->sd_, sa_, oStarDictClient->port_, oStarDictClient, on_connected); -+} -+ -+void StarDictClient::on_connected(gpointer data, bool succeeded) -+{ -+ StarDictClient *oStarDictClient = (StarDictClient *)data; -+ if (!succeeded) { -+ static bool showed_once = false; -+ if (!showed_once) { -+ showed_once = true; -+ gchar *mes = g_strdup_printf("Can not connect to %s: %s\n", -+ oStarDictClient->host_.c_str(), Socket::get_error_msg().c_str()); -+ on_error_.emit(mes); -+ g_free(mes); -+ } -+ return; -+ } -+#ifdef _WIN32 -+ oStarDictClient->channel_ = g_io_channel_win32_new_socket(oStarDictClient->sd_); -+#else -+ oStarDictClient->channel_ = g_io_channel_unix_new(oStarDictClient->sd_); -+#endif -+ -+ g_io_channel_set_encoding(oStarDictClient->channel_, NULL, NULL); -+ -+ /* make sure that the channel is non-blocking */ -+ int flags = g_io_channel_get_flags(oStarDictClient->channel_); -+ flags |= G_IO_FLAG_NONBLOCK; -+ GError *err = NULL; -+ g_io_channel_set_flags(oStarDictClient->channel_, GIOFlags(flags), &err); -+ if (err) { -+ g_io_channel_unref(oStarDictClient->channel_); -+ oStarDictClient->channel_ = NULL; -+ gchar *str = g_strdup_printf("Unable to set the channel as non-blocking: %s", err->message); -+ on_error_.emit(str); -+ g_free(str); -+ g_error_free(err); -+ return; -+ } -+ -+ oStarDictClient->is_connected_ = true; -+ oStarDictClient->waiting_banner_ = true; -+ oStarDictClient->reading_type_ = READ_LINE; -+ oStarDictClient->in_source_id_ = g_io_add_watch(oStarDictClient->channel_, GIOCondition(G_IO_IN | G_IO_ERR), on_io_in_event, oStarDictClient); -+} -+ -+void StarDictClient::disconnect() -+{ -+ clean_command(); -+ if (in_source_id_) { -+ g_source_remove(in_source_id_); -+ in_source_id_ = 0; -+ } -+ if (out_source_id_) { -+ g_source_remove(out_source_id_); -+ out_source_id_ = 0; -+ } -+ -+ if (channel_) { -+ g_io_channel_shutdown(channel_, TRUE, NULL); -+ g_io_channel_unref(channel_); -+ channel_ = NULL; -+ } -+ if (sd_ != -1) { -+ Socket::close(sd_); -+ sd_ = -1; -+ } -+ is_connected_ = false; -+} -+ -+gboolean StarDictClient::on_io_out_event(GIOChannel *ch, GIOCondition cond, -+ gpointer user_data) -+{ -+ StarDictClient *stardict_client = static_cast<StarDictClient *>(user_data); -+ GError *err = NULL; -+ GIOStatus res = g_io_channel_flush(stardict_client->channel_, &err); -+ if (res == G_IO_STATUS_AGAIN) { -+ return TRUE; -+ } else if (err) { -+ on_error_.emit(err->message); -+ g_error_free(err); -+ } -+ stardict_client->out_source_id_ = 0; -+ return FALSE; -+} -+ -+gboolean StarDictClient::on_io_in_event(GIOChannel *ch, GIOCondition cond, -+ gpointer user_data) -+{ -+ StarDictClient *stardict_client = static_cast<StarDictClient *>(user_data); -+ -+ if (!stardict_client->channel_) { -+ //g_warning("No channel available\n"); -+ return FALSE; -+ } -+ if (cond & G_IO_ERR) { -+ /*gchar *mes = -+ g_strdup_printf("Connection failed to the dictionary server at %s:%d", -+ stardict_client->host_.c_str(), stardict_client->port_); -+ on_error_.emit(mes); -+ g_free(mes);*/ -+ stardict_client->disconnect(); -+ return FALSE; -+ } -+ GError *err = NULL; -+ gsize term, len; -+ gchar *line; -+ GIOStatus res; -+ -+ for (;;) { -+ if (!stardict_client->channel_) -+ break; -+ bool result; -+ if (stardict_client->reading_type_ == READ_SIZE) { -+ gsize bytes_read; -+ res = g_io_channel_read_chars(stardict_client->channel_, stardict_client->size_data+(stardict_client->size_count-stardict_client->size_left), stardict_client->size_left, &bytes_read, &err); -+ if (res == G_IO_STATUS_ERROR || res == G_IO_STATUS_EOF) { -+ if (err) { -+ gchar *str = g_strdup_printf("Error while reading reply from server: %s", err->message); -+ on_error_.emit(str); -+ g_free(str); -+ g_error_free(err); -+ } -+ stardict_client->disconnect(); -+ -+ return FALSE; -+ } -+ stardict_client->size_left -= bytes_read; -+ if (stardict_client->size_left == 0) -+ result = stardict_client->parse(stardict_client->size_data); -+ else -+ break; -+ } else { -+ if (stardict_client->reading_type_ == READ_LINE) -+ g_io_channel_set_line_term(stardict_client->channel_, "\n", 1); -+ else if (stardict_client->reading_type_ == READ_STRING) -+ g_io_channel_set_line_term(stardict_client->channel_, "", 1); -+ -+ res = g_io_channel_read_line(stardict_client->channel_, &line, -+ &len, &term, &err); -+ if (res == G_IO_STATUS_ERROR || res == G_IO_STATUS_EOF) { -+ if (err) { -+ gchar *str = g_strdup_printf("Error while reading reply from server: %s", err->message); -+ on_error_.emit(str); -+ g_free(str); -+ g_error_free(err); -+ } -+ stardict_client->disconnect(); -+ -+ return FALSE; -+ } -+ -+ if (!len) -+ break; -+ -+ //truncate the line terminator before parsing -+ line[term] = '\0'; -+ result = stardict_client->parse(line); -+ } -+ if (!result) { -+ stardict_client->disconnect(); -+ return FALSE; -+ } -+ } -+ -+ return TRUE; -+} -+ -+int StarDictClient::parse_banner(gchar *line) -+{ -+ int status; -+ status = atoi(line); -+ if (status != CODE_HELLO) { -+ if (status == CODE_TEMPORARILY_UNAVAILABLE) { -+ printf("Server temporarily unavailable!\n"); -+ } else { -+ printf("Unexpected status code %d\n", status); -+ } -+ return 0; -+ } -+ char *p; -+ p = strrchr(line, ' '); -+ if (p) { -+ p++; -+ cmd_reply.daemonStamp = p; -+ } -+ return 1; -+} -+ -+int StarDictClient::parse_command_client(gchar *line) -+{ -+ int status; -+ status = atoi(line); -+ if (status != CODE_OK) { -+ gchar *str = g_strdup_printf("Client denied: %s", line); -+ on_error_.emit(str); -+ g_free(str); -+ return 0; -+ } -+ return 1; -+} -+ -+int StarDictClient::parse_command_auth(gchar *line) -+{ -+ int status; -+ status = atoi(line); -+ if (status != CODE_OK) { -+ gchar *str = g_strdup_printf(_("Authentication denied: %s"), line); -+ on_error_.emit(str); -+ g_free(str); -+ return 0; -+ } -+ return 1; -+} -+ -+int StarDictClient::parse_command_register(gchar *line) -+{ -+ int status; -+ status = atoi(line); -+ if (status != CODE_OK) { -+ gchar *str = g_strdup_printf(_("Register failed: %s"), line); -+ on_error_.emit(str); -+ g_free(str); -+ return 0; -+ } -+ on_register_end_.emit(_("Register success!")); -+ return 1; -+} -+ -+int StarDictClient::parse_command_quit(gchar *line) -+{ -+ int status; -+ status = atoi(line); -+ if (status != CODE_GOODBYE) { -+ } -+ return 0; -+} -+ -+int StarDictClient::parse_command_setdictmask(gchar *line) -+{ -+ int status; -+ status = atoi(line); -+ if (status != CODE_OK) { -+ gchar *str = g_strdup_printf("Set Dict Mask failed: %s", line); -+ on_error_.emit(str); -+ g_free(str); -+ return 0; -+ } -+ clean_cache_str("getdictmask\n"); -+ clean_cache_lookup_response(); -+ return 1; -+} -+ -+int StarDictClient::parse_command_getdictmask(STARDICT::Cmd* cmd, gchar *buf) -+{ -+ if (cmd->reading_status == 0) { -+ int status; -+ status = atoi(buf); -+ if (status != CODE_OK) { -+ g_free(buf); -+ on_error_.emit(_("You haven't setup the account. Please open the \"Net Dict\" page in the Preferences dialog and register an account first.")); -+ return 0; -+ } -+ g_free(buf); -+ cmd->reading_status = 1; -+ reading_type_ = READ_STRING; -+ } else if (cmd->reading_status == 1) { -+ on_getdictmask_end_.emit(buf); -+ save_cache_str(cmd->data, buf); -+ return 1; -+ } -+ return 2; -+} -+ -+int StarDictClient::parse_command_dirinfo(STARDICT::Cmd* cmd, gchar *buf) -+{ -+ if (cmd->reading_status == 0) { -+ int status; -+ status = atoi(buf); -+ if (status != CODE_OK) { -+ gchar *str = g_strdup_printf("Get dir info failed: %s", buf); -+ g_free(buf); -+ on_error_.emit(str); -+ g_free(str); -+ return 0; -+ } -+ g_free(buf); -+ cmd->reading_status = 1; -+ reading_type_ = READ_STRING; -+ } else if (cmd->reading_status == 1) { -+ on_dirinfo_end_.emit(buf); -+ save_cache_str(cmd->data, buf); -+ return 1; -+ } -+ return 2; -+} -+ -+int StarDictClient::parse_command_dictinfo(STARDICT::Cmd* cmd, gchar *buf) -+{ -+ if (cmd->reading_status == 0) { -+ int status; -+ status = atoi(buf); -+ if (status != CODE_OK) { -+ gchar *str = g_strdup_printf("Get dict info failed: %s", buf); -+ g_free(buf); -+ on_error_.emit(str); -+ g_free(str); -+ return 0; -+ } -+ g_free(buf); -+ cmd->reading_status = 1; -+ reading_type_ = READ_STRING; -+ } else if (cmd->reading_status == 1) { -+ on_dictinfo_end_.emit(buf); -+ save_cache_str(cmd->data, buf); -+ return 1; -+ } -+ return 2; -+} -+ -+int StarDictClient::parse_command_maxdictcount(STARDICT::Cmd* cmd, gchar *buf) -+{ -+ if (cmd->reading_status == 0) { -+ int status; -+ status = atoi(buf); -+ if (status != CODE_OK) { -+ gchar *str = g_strdup_printf("Get max dict count failed: %s", buf); -+ g_free(buf); -+ on_error_.emit(str); -+ g_free(str); -+ return 0; -+ } -+ g_free(buf); -+ cmd->reading_status = 1; -+ reading_type_ = READ_STRING; -+ } else if (cmd->reading_status == 1) { -+ on_maxdictcount_end_.emit(atoi(buf)); -+ save_cache_str(cmd->data, buf); -+ return 1; -+ } -+ return 2; -+} -+ -+int StarDictClient::parse_wordlist(STARDICT::Cmd* cmd, gchar *buf) -+{ -+ if (cmd->reading_status == 0) { // Read code. -+ int status; -+ status = atoi(buf); -+ g_free(buf); -+ if (status != CODE_OK) { -+ return 0; -+ } -+ cmd->wordlist_response = new std::list<char *>; -+ cmd->reading_status = 1; -+ reading_type_ = READ_STRING; -+ } else if (cmd->reading_status == 1) { -+ if (*buf == '\0') { -+ g_free(buf); -+ if (cmd->command == STARDICT::CMD_PREVIOUS) { -+ on_previous_end_.emit(cmd->wordlist_response); -+ return 1; -+ } else { -+ on_next_end_.emit(cmd->wordlist_response); -+ return 1; -+ } -+ } else { -+ cmd->wordlist_response->push_back(buf); -+ } -+ } -+ return 2; -+} -+ -+int StarDictClient::parse_dict_result(STARDICT::Cmd* cmd, gchar *buf) -+{ -+ if (cmd->reading_status == 0) { // Read code. -+ int status; -+ status = atoi(buf); -+ g_free(buf); -+ if (status != CODE_OK) { -+ if (status == CODE_DICTMASK_NOTSET) { -+ on_error_.emit(_("You haven't chosen any dictionaries, please choose some by clicking \"Manage Dict\"->\"Network dictionaries\"->\"Add\".")); -+ return 1; -+ } else { -+ return 0; -+ } -+ } -+ cmd->lookup_response = new STARDICT::LookupResponse(); -+ cmd->lookup_response->listtype = STARDICT::LookupResponse::ListType_None; -+ cmd->reading_status = 1; -+ reading_type_ = READ_STRING; -+ } else if (cmd->reading_status == 1) { // Read original word. -+ cmd->lookup_response->dict_response.oword = buf; -+ cmd->reading_status = 2; -+ } else if (cmd->reading_status == 2) { // Read book name. -+ if (*buf == '\0') { -+ g_free(buf); -+ if (cmd->command == STARDICT::CMD_DEFINE) { -+ on_lookup_end_.emit(cmd->lookup_response, cmd->seq); -+ save_cache_lookup_response(cmd->data, cmd->lookup_response); -+ cmd->lookup_response = NULL; -+ return 1; -+ } else if ( cmd->command == STARDICT::CMD_SELECT_QUERY || cmd->command == STARDICT::CMD_SMART_QUERY) { -+ on_floatwin_lookup_end_.emit(cmd->lookup_response, cmd->seq); -+ save_cache_lookup_response(cmd->data, cmd->lookup_response); -+ cmd->lookup_response = NULL; -+ return 1; -+ } -+ cmd->reading_status = 6; -+ reading_type_ = READ_STRING; -+ } else { -+ struct STARDICT::LookupResponse::DictResponse::DictResult *dict_result = new STARDICT::LookupResponse::DictResponse::DictResult(); -+ dict_result->bookname = buf; -+ cmd->lookup_response->dict_response.dict_result_list.push_back(dict_result); -+ cmd->reading_status = 3; -+ } -+ } else if (cmd->reading_status == 3) { // Read word. -+ if (*buf == '\0') { -+ g_free(buf); -+ cmd->reading_status = 2; -+ } else { -+ struct STARDICT::LookupResponse::DictResponse::DictResult::WordResult *word_result = new STARDICT::LookupResponse::DictResponse::DictResult::WordResult(); -+ word_result->word = buf; -+ cmd->lookup_response->dict_response.dict_result_list.back()->word_result_list.push_back(word_result);; -+ cmd->reading_status = 4; -+ reading_type_ = READ_SIZE; -+ size_data = (char *)g_malloc(sizeof(guint32)); -+ size_count = size_left = sizeof(guint32); -+ } -+ } else if (cmd->reading_status == 4) { -+ guint32 datasize = g_ntohl(get_uint32(buf)); -+ memcpy(buf, &datasize, sizeof(guint32)); -+ if (datasize == 0) { -+ g_free(buf); -+ cmd->reading_status = 3; -+ reading_type_ = READ_STRING; -+ } else { -+ cmd->reading_status = 5; -+ size_data = (char *)g_realloc(buf, datasize + sizeof(guint32)); -+ size_count = datasize + sizeof(guint32); -+ size_left = datasize; -+ } -+ } else if (cmd->reading_status == 5) { -+ cmd->lookup_response->dict_response.dict_result_list.back()->word_result_list.back()->datalist.push_back(buf); -+ cmd->reading_status = 4; -+ size_data = (char *)g_malloc(sizeof(guint32)); -+ size_count = size_left = sizeof(guint32); -+ } else if (cmd->reading_status == 6) { -+ if (strcmp(buf, "d") == 0) { -+ cmd->reading_status = 8; -+ cmd->lookup_response->listtype = STARDICT::LookupResponse::ListType_Tree; -+ cmd->lookup_response->wordtree = new std::list<STARDICT::LookupResponse::WordTreeElement *>; -+ } else { -+ cmd->reading_status = 7; -+ if (strcmp(buf, "r") == 0) -+ cmd->lookup_response->listtype = STARDICT::LookupResponse::ListType_Rule_List; -+ else if (strcmp(buf, "g") == 0) -+ cmd->lookup_response->listtype = STARDICT::LookupResponse::ListType_Regex_List; -+ else if (strcmp(buf, "f") == 0) -+ cmd->lookup_response->listtype = STARDICT::LookupResponse::ListType_Fuzzy_List; -+ else -+ cmd->lookup_response->listtype = STARDICT::LookupResponse::ListType_List; -+ cmd->lookup_response->wordlist = new std::list<char *>; -+ } -+ g_free(buf); -+ } else if (cmd->reading_status == 7) { -+ if (*buf == '\0') { -+ g_free(buf); -+ on_lookup_end_.emit(cmd->lookup_response, cmd->seq); -+ save_cache_lookup_response(cmd->data, cmd->lookup_response); -+ cmd->lookup_response = NULL; -+ return 1; -+ } else { -+ cmd->lookup_response->wordlist->push_back(buf); -+ } -+ } else if (cmd->reading_status == 8) { -+ if (*buf == '\0') { -+ g_free(buf); -+ on_lookup_end_.emit(cmd->lookup_response, cmd->seq); -+ save_cache_lookup_response(cmd->data, cmd->lookup_response); -+ cmd->lookup_response = NULL; -+ return 1; -+ } else { -+ STARDICT::LookupResponse::WordTreeElement *element = new STARDICT::LookupResponse::WordTreeElement(); -+ element->bookname = buf; -+ cmd->lookup_response->wordtree->push_back(element); -+ cmd->reading_status = 9; -+ } -+ } else if (cmd->reading_status == 9) { -+ if (*buf == '\0') { -+ g_free(buf); -+ cmd->reading_status = 8; -+ } else { -+ cmd->lookup_response->wordtree->back()->wordlist.push_back(buf); -+ } -+ } -+ return 2; -+} -+ -+bool StarDictClient::parse(gchar *line) -+{ -+ int result; -+ if (waiting_banner_) { -+ waiting_banner_ = false; -+ result = parse_banner(line); -+ g_free(line); -+ if (!result) -+ return false; -+ request_command(); -+ return true; -+ } -+ STARDICT::Cmd* cmd = cmdlist.front(); -+ switch (cmd->command) { -+ case STARDICT::CMD_CLIENT: -+ result = parse_command_client(line); -+ g_free(line); -+ break; -+ case STARDICT::CMD_AUTH: -+ result = parse_command_auth(line); -+ g_free(line); -+ break; -+ case STARDICT::CMD_REGISTER: -+ result = parse_command_register(line); -+ g_free(line); -+ break; -+ case STARDICT::CMD_GET_DICT_MASK: -+ result = parse_command_getdictmask(cmd, line); -+ break; -+ case STARDICT::CMD_SET_DICT_MASK: -+ result = parse_command_setdictmask(line); -+ break; -+ case STARDICT::CMD_DIR_INFO: -+ result = parse_command_dirinfo(cmd, line); -+ break; -+ case STARDICT::CMD_DICT_INFO: -+ result = parse_command_dictinfo(cmd, line); -+ break; -+ case STARDICT::CMD_MAX_DICT_COUNT: -+ result = parse_command_maxdictcount(cmd, line); -+ break; -+ case STARDICT::CMD_DEFINE: -+ case STARDICT::CMD_LOOKUP: -+ case STARDICT::CMD_SELECT_QUERY: -+ case STARDICT::CMD_SMART_QUERY: -+ result = parse_dict_result(cmd, line); -+ break; -+ case STARDICT::CMD_PREVIOUS: -+ case STARDICT::CMD_NEXT: -+ result = parse_wordlist(cmd, line); -+ break; -+ case STARDICT::CMD_QUIT: -+ result = parse_command_quit(line); -+ g_free(line); -+ break; -+ default: -+ result = 0; -+ g_free(line); -+ break; -+ } -+ if (result == 0) -+ return false; -+ if (result == 1) { -+ delete cmd; -+ cmdlist.pop_front(); -+ if (cmdlist.empty()) { -+ cmdlist.push_back(new STARDICT::Cmd(STARDICT::CMD_QUIT)); -+ } -+ request_command(); -+ } -+ return true; -+} -diff -Nur stardict-3.0.1.orig//src/lib/stddict.cpp stardict-3.0.1/src/lib/stddict.cpp ---- stardict-3.0.1.orig//src/lib/stddict.cpp 2007-10-30 04:06:07.000000000 -0500 -+++ stardict-3.0.1/src/lib/stddict.cpp 2010-05-24 00:53:36.377667178 -0500 -@@ -39,6 +39,7 @@ - #include "stddict.hpp" - #include <algorithm> - #include "getuint32.h" -+#include <cstring> - - static inline gint stardict_strcmp(const gchar *s1, const gchar *s2) - { -diff -Nur stardict-3.0.1.orig//src/lib/stddict.cpp~ stardict-3.0.1/src/lib/stddict.cpp~ ---- stardict-3.0.1.orig//src/lib/stddict.cpp~ 1969-12-31 18:00:00.000000000 -0600 -+++ stardict-3.0.1/src/lib/stddict.cpp~ 2007-10-30 04:06:07.000000000 -0500 -@@ -0,0 +1,3263 @@ -+/* -+ * This file part of StarDict - A international dictionary for GNOME. -+ * http://stardict.sourceforge.net -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 3 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU Library General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -+ */ -+ -+/* -+ * Implementation of class to work with standard StarDict's dictionaries -+ * lookup word, get articles and so on. -+ * -+ * Notice: read doc/DICTFILE_FORMAT for the dictionary -+ * file's format information! -+ */ -+#ifdef HAVE_CONFIG_H -+# include "config.h" -+#endif -+ -+#include <glib/gi18n.h> -+#include <glib/gstdio.h> -+ -+#include "common.hpp" -+#include "distance.h" -+#include "kmp.h" -+#include "mapfile.hpp" -+ -+#include "stddict.hpp" -+#include <algorithm> -+#include "getuint32.h" -+ -+static inline gint stardict_strcmp(const gchar *s1, const gchar *s2) -+{ -+ gint a=g_ascii_strcasecmp(s1, s2); -+ if (a == 0) -+ return strcmp(s1, s2); -+ else -+ return a; -+} -+ -+static gint stardict_collate(const gchar *str1, const gchar *str2, CollateFunctions func) -+{ -+ gint x = utf8_collate(str1, str2, func); -+ if (x == 0) -+ return strcmp(str1, str2); -+ else -+ return x; -+} -+ -+gint stardict_server_collate(const gchar *str1, const gchar *str2, int EnableCollationLevel, CollateFunctions func, int servercollatefunc) -+{ -+ if (EnableCollationLevel == 0) -+ return stardict_strcmp(str1, str2); -+ if (EnableCollationLevel == 1) -+ return stardict_collate(str1, str2, func); -+ if (servercollatefunc == 0) -+ return stardict_strcmp(str1, str2); -+ return stardict_collate(str1, str2, (CollateFunctions)(servercollatefunc-1)); -+} -+ -+gint stardict_casecmp(const gchar *s1, const gchar *s2, int EnableCollationLevel, CollateFunctions func, int servercollatefunc) -+{ -+ if (EnableCollationLevel == 0) -+ return g_ascii_strcasecmp(s1, s2); -+ if (EnableCollationLevel == 1) -+ return utf8_collate(s1, s2, func); -+ if (servercollatefunc == 0) -+ return g_ascii_strcasecmp(s1, s2); -+ return utf8_collate(s1, s2, (CollateFunctions)(servercollatefunc-1)); -+} -+ -+static inline gint prefix_match (const gchar *s1, const gchar *s2) -+{ -+ gint ret=-1; -+ gunichar u1, u2; -+ do { -+ u1 = g_utf8_get_char(s1); -+ u2 = g_utf8_get_char(s2); -+ s1 = g_utf8_next_char(s1); -+ s2 = g_utf8_next_char(s2); -+ ret++; -+ } while (u1 && g_unichar_tolower(u1) == g_unichar_tolower(u2)); -+ return ret; -+} -+ -+static inline bool bIsVowel(gchar inputchar) -+{ -+ gchar ch = g_ascii_toupper(inputchar); -+ return( ch=='A' || ch=='E' || ch=='I' || ch=='O' || ch=='U' ); -+} -+ -+ -+bool bIsPureEnglish(const gchar *str) -+{ -+ // i think this should work even when it is UTF8 string :). -+ for (int i=0; str[i]!=0; i++) -+ //if(str[i]<0) -+ //if(str[i]<32 || str[i]>126) // tab equal 9,so this is not OK. -+ // Better use isascii() but not str[i]<0 while char is default unsigned in arm -+ if (!isascii(str[i])) -+ return false; -+ return true; -+} -+ -+class offset_index : public index_file { -+public: -+ offset_index(); -+ ~offset_index(); -+ bool load(const std::string& url, gulong wc, gulong fsize, -+ bool CreateCacheFile, int EnableCollationLevel, -+ CollateFunctions _CollateFunction, show_progress_t *sp); -+ void get_data(glong idx); -+ const gchar *get_key_and_data(glong idx); -+private: -+ const gchar *get_key(glong idx); -+ bool lookup(const char *str, glong &idx, glong &idx_suggest); -+ -+ static const gint ENTR_PER_PAGE=32; -+ -+ cache_file oft_file; -+ FILE *idxfile; -+ gulong npages; -+ -+ gchar wordentry_buf[256+sizeof(guint32)*2]; // The length of "word_str" should be less than 256. See doc/DICTFILE_FORMAT. -+ struct index_entry { -+ glong idx; -+ std::string keystr; -+ void assign(glong i, const std::string& str) { -+ idx=i; -+ keystr.assign(str); -+ } -+ }; -+ index_entry first, last, middle, real_last; -+ -+ struct page_entry { -+ gchar *keystr; -+ guint32 off, size; -+ }; -+ std::vector<gchar> page_data; -+ struct page_t { -+ glong idx; -+ page_entry entries[ENTR_PER_PAGE]; -+ -+ page_t(): idx(-1) {} -+ void fill(gchar *data, gint nent, glong idx_); -+ } page; -+ gulong load_page(glong page_idx); -+ const gchar *read_first_on_page_key(glong page_idx); -+ const gchar *get_first_on_page_key(glong page_idx); -+}; -+ -+class wordlist_index : public index_file { -+public: -+ wordlist_index(); -+ ~wordlist_index(); -+ bool load(const std::string& url, gulong wc, gulong fsize, -+ bool CreateCacheFile, int EnableCollationLevel, -+ CollateFunctions _CollateFunction, show_progress_t *sp); -+ void get_data(glong idx); -+ const gchar *get_key_and_data(glong idx); -+private: -+ const gchar *get_key(glong idx); -+ bool lookup(const char *str, glong &idx, glong &idx_suggest); -+ -+ gchar *idxdatabuf; -+ std::vector<gchar *> wordlist; -+}; -+ -+offset_index::offset_index() : oft_file(CacheFileType_oft) -+{ -+ clt_file = NULL; -+ idxfile = NULL; -+} -+ -+offset_index::~offset_index() -+{ -+ delete clt_file; -+ if (idxfile) -+ fclose(idxfile); -+} -+ -+void offset_index::page_t::fill(gchar *data, gint nent, glong idx_) -+{ -+ idx=idx_; -+ gchar *p=data; -+ glong len; -+ for (gint i=0; i<nent; ++i) { -+ entries[i].keystr=p; -+ len=strlen(p); -+ p+=len+1; -+ entries[i].off=g_ntohl(get_uint32(p)); -+ p+=sizeof(guint32); -+ entries[i].size=g_ntohl(get_uint32(p)); -+ p+=sizeof(guint32); -+ } -+} -+ -+inline const gchar *offset_index::read_first_on_page_key(glong page_idx) -+{ -+ fseek(idxfile, oft_file.wordoffset[page_idx], SEEK_SET); -+ guint32 page_size=oft_file.wordoffset[page_idx+1]-oft_file.wordoffset[page_idx]; -+ gulong minsize = sizeof(wordentry_buf); -+ if (page_size < minsize) -+ minsize = page_size; -+ fread(wordentry_buf, minsize, 1, idxfile); //TODO: check returned values, deal with word entry that strlen>255. -+ return wordentry_buf; -+} -+ -+inline const gchar *offset_index::get_first_on_page_key(glong page_idx) -+{ -+ if (page_idx<middle.idx) { -+ if (page_idx==first.idx) -+ return first.keystr.c_str(); -+ return read_first_on_page_key(page_idx); -+ } else if (page_idx>middle.idx) { -+ if (page_idx==last.idx) -+ return last.keystr.c_str(); -+ return read_first_on_page_key(page_idx); -+ } else -+ return middle.keystr.c_str(); -+} -+ -+cache_file::cache_file(CacheFileType _cachefiletype) -+{ -+ wordoffset = NULL; -+ mf = NULL; -+ cachefiletype = _cachefiletype; -+} -+ -+ -+cache_file::~cache_file() -+{ -+ if (mf) -+ delete mf; -+ else -+ g_free(wordoffset); -+} -+ -+#define OFFSETFILE_MAGIC_DATA "StarDict's oft file\nversion=2.4.8\n" -+#define COLLATIONFILE_MAGIC_DATA "StarDict's clt file\nversion=2.4.8\n" -+ -+MapFile* cache_file::get_cache_loadfile(const gchar *filename, const std::string &url, const std::string &saveurl, CollateFunctions cltfunc, glong filedatasize, int next) -+{ -+ struct stat cachestat; -+ if (g_stat(filename, &cachestat)!=0) -+ return NULL; -+ MapFile *mf = new MapFile; -+ if (!mf->open(filename, cachestat.st_size)) { -+ delete mf; -+ return NULL; -+ } -+ -+ gchar *p = mf->begin(); -+ gboolean has_prefix; -+ if (cachefiletype == CacheFileType_oft) -+ has_prefix = g_str_has_prefix(p, OFFSETFILE_MAGIC_DATA); -+ else -+ has_prefix = g_str_has_prefix(p, COLLATIONFILE_MAGIC_DATA); -+ if (!has_prefix) { -+ delete mf; -+ return NULL; -+ } -+ if (cachefiletype == CacheFileType_oft) -+ p+= sizeof(OFFSETFILE_MAGIC_DATA)-1-1; -+ else -+ p+= sizeof(COLLATIONFILE_MAGIC_DATA)-1-1; -+ gchar *p2; -+ p2 = strstr(p, "\nurl="); -+ if (!p2) { -+ delete mf; -+ return NULL; -+ } -+ p2+=sizeof("\nurl=")-1; -+ gchar *p3; -+ p3 = strchr(p2, '\n'); -+ if (!p3) { -+ delete mf; -+ return NULL; -+ } -+ gchar *tmpstr; -+ tmpstr = (gchar *)g_memdup(p2, p3-p2+1); -+ tmpstr[p3-p2] = '\0'; -+ if (saveurl == tmpstr) { -+ g_free(tmpstr); -+ if (cachefiletype == CacheFileType_clt) { -+ p2 = strstr(p, "\nfunc="); -+ if (!p2) { -+ delete mf; -+ return NULL; -+ } -+ p2+=sizeof("\nfunc=")-1; -+ p3 = strchr(p2, '\n'); -+ if (!p3) { -+ delete mf; -+ return NULL; -+ } -+ tmpstr = (gchar *)g_memdup(p2, p3-p2+1); -+ tmpstr[p3-p2] = '\0'; -+ if (atoi(tmpstr)!=cltfunc) { -+ g_free(tmpstr); -+ delete mf; -+ return NULL; -+ } -+ g_free(tmpstr); -+ } -+ if (cachestat.st_size!=glong(filedatasize + strlen(mf->begin()) +1)) { -+ delete mf; -+ return NULL; -+ } -+ struct stat idxstat; -+ if (g_stat(url.c_str(), &idxstat)!=0) { -+ delete mf; -+ return NULL; -+ } -+ if (cachestat.st_mtime<idxstat.st_mtime) { -+ delete mf; -+ return NULL; -+ } -+ //g_print("Using map file: %s\n", filename); -+ return mf; -+ } -+ g_free(tmpstr); -+ delete mf; -+ gchar *basename = g_path_get_basename(saveurl.c_str()); -+ p = strrchr(basename, '.'); -+ if (!p) { -+ g_free(basename); -+ return NULL; -+ } -+ *p='\0'; -+ gchar *extendname = p+1; -+ gchar *dirname = g_path_get_dirname(filename); -+ gchar *nextfilename; -+ if (cachefiletype == CacheFileType_oft) -+ nextfilename = g_strdup_printf("%s" G_DIR_SEPARATOR_S "%s(%d).%s.oft", dirname, basename, next, extendname); -+ else if (cachefiletype == CacheFileType_clt) -+ nextfilename = g_strdup_printf("%s" G_DIR_SEPARATOR_S "%s(%d).%s.clt", dirname, basename, next, extendname); -+ else -+ nextfilename = g_strdup_printf("%s" G_DIR_SEPARATOR_S "%s(%d).%s.%d.clt", dirname, basename, next, extendname, cltfunc); -+ MapFile *out = get_cache_loadfile(nextfilename, url, saveurl, cltfunc, filedatasize, next+1); -+ g_free(basename); -+ g_free(dirname); -+ g_free(nextfilename); -+ return out; -+} -+ -+bool cache_file::load_cache(const std::string& url, const std::string& saveurl, CollateFunctions cltfunc, glong filedatasize) -+{ -+ std::string oftfilename; -+ if (cachefiletype == CacheFileType_oft) -+ oftfilename=saveurl+".oft"; -+ else if (cachefiletype == CacheFileType_clt) -+ oftfilename=saveurl+".clt"; -+ else { -+ gchar *func = g_strdup_printf("%d", cltfunc); -+ oftfilename=saveurl+'.'+func+".clt"; -+ g_free(func); -+ } -+ for (int i=0;i<2;i++) { -+ if (i==1) { -+ if (!get_cache_filename(saveurl, oftfilename, false, cltfunc)) -+ break; -+ } -+ mf = get_cache_loadfile(oftfilename.c_str(), url, saveurl, cltfunc, filedatasize, 2); -+ if (!mf) -+ continue; -+ wordoffset = (guint32 *)(mf->begin()+strlen(mf->begin())+1); -+ return true; -+ } -+ return false; -+} -+ -+bool cache_file::get_cache_filename(const std::string& url, std::string &cachefilename, bool create, CollateFunctions cltfunc) -+{ -+ if (create) { -+ if (!g_file_test(g_get_user_cache_dir(), G_FILE_TEST_EXISTS) && -+ g_mkdir(g_get_user_cache_dir(), 0700)==-1) -+ return false; -+ } -+ -+ std::string cache_dir=g_get_user_cache_dir(); -+ cache_dir += G_DIR_SEPARATOR_S "stardict"; -+ -+ if (create) { -+ if (!g_file_test(cache_dir.c_str(), G_FILE_TEST_EXISTS)) { -+ if (g_mkdir(cache_dir.c_str(), 0700)==-1) -+ return false; -+ } else if (!g_file_test(cache_dir.c_str(), G_FILE_TEST_IS_DIR)) -+ return false; -+ } -+ -+ gchar *base=g_path_get_basename(url.c_str()); -+ if (cachefiletype == CacheFileType_oft) { -+ cachefilename = cache_dir+G_DIR_SEPARATOR_S+base+".oft"; -+ } else if (cachefiletype == CacheFileType_clt) { -+ cachefilename = cache_dir+G_DIR_SEPARATOR_S+base+".clt"; -+ } else { -+ gchar *func = g_strdup_printf("%d", cltfunc); -+ cachefilename = cache_dir+G_DIR_SEPARATOR_S+base+'.'+func+".clt"; -+ g_free(func); -+ } -+ g_free(base); -+ return true; -+} -+ -+FILE* cache_file::get_cache_savefile(const gchar *filename, const std::string &url, int next, std::string &cfilename, CollateFunctions cltfunc) -+{ -+ cfilename = filename; -+ struct stat oftstat; -+ if (g_stat(filename, &oftstat)!=0) { -+ return fopen(filename, "wb"); -+ } -+ MapFile mf; -+ if (!mf.open(filename, oftstat.st_size)) { -+ return fopen(filename, "wb"); -+ } -+ gchar *p = mf.begin(); -+ bool has_prefix; -+ if (cachefiletype == CacheFileType_oft) -+ has_prefix = g_str_has_prefix(p, OFFSETFILE_MAGIC_DATA); -+ else -+ has_prefix = g_str_has_prefix(p, COLLATIONFILE_MAGIC_DATA); -+ if (!has_prefix) { -+ mf.close(); -+ return fopen(filename, "wb"); -+ } -+ if (cachefiletype == CacheFileType_oft) -+ p+= sizeof(OFFSETFILE_MAGIC_DATA)-1-1; -+ else -+ p+= sizeof(COLLATIONFILE_MAGIC_DATA)-1-1; -+ gchar *p2; -+ p2 = strstr(p, "\nurl="); -+ if (!p2) { -+ mf.close(); -+ return fopen(filename, "wb"); -+ } -+ p2+=sizeof("\nurl=")-1; -+ gchar *p3; -+ p3 = strchr(p2, '\n'); -+ if (!p3) { -+ mf.close(); -+ return fopen(filename, "wb"); -+ } -+ gchar *tmpstr; -+ tmpstr = (gchar *)g_memdup(p2, p3-p2+1); -+ tmpstr[p3-p2] = '\0'; -+ if (url == tmpstr) { -+ g_free(tmpstr); -+ mf.close(); -+ return fopen(filename, "wb"); -+ } -+ g_free(tmpstr); -+ mf.close(); -+ gchar *basename = g_path_get_basename(url.c_str()); -+ p = strrchr(basename, '.'); -+ if (!p) { -+ g_free(basename); -+ return NULL; -+ } -+ *p='\0'; -+ gchar *extendname = p+1; -+ gchar *dirname = g_path_get_dirname(filename); -+ gchar *nextfilename; -+ if (cachefiletype == CacheFileType_oft) -+ nextfilename = g_strdup_printf("%s" G_DIR_SEPARATOR_S "%s(%d).%s.oft", dirname, basename, next, extendname); -+ else if (cachefiletype == CacheFileType_clt) -+ nextfilename = g_strdup_printf("%s" G_DIR_SEPARATOR_S "%s(%d).%s.clt", dirname, basename, next, extendname); -+ else -+ nextfilename = g_strdup_printf("%s" G_DIR_SEPARATOR_S "%s(%d).%s.%d.clt", dirname, basename, next, extendname, cltfunc); -+ FILE *out = get_cache_savefile(nextfilename, url, next+1, cfilename, cltfunc); -+ g_free(basename); -+ g_free(dirname); -+ g_free(nextfilename); -+ return out; -+} -+ -+bool cache_file::save_cache(const std::string& url, CollateFunctions cltfunc, gulong npages) -+{ -+ std::string oftfilename; -+ if (cachefiletype == CacheFileType_oft) { -+ oftfilename=url+".oft"; -+ } else if (cachefiletype == CacheFileType_clt) { -+ oftfilename=url+".clt"; -+ } else { -+ gchar *func = g_strdup_printf("%d", cltfunc); -+ oftfilename=url+'.'+func+".clt"; -+ g_free(func); -+ } -+ for (int i=0;i<2;i++) { -+ if (i==1) { -+ if (!get_cache_filename(url, oftfilename, true, cltfunc)) -+ break; -+ } -+ std::string cfilename; -+ FILE *out= get_cache_savefile(oftfilename.c_str(), url, 2, cfilename, cltfunc); -+ if (!out) -+ continue; -+ if (cachefiletype == CacheFileType_oft) -+ fwrite(OFFSETFILE_MAGIC_DATA, 1, sizeof(OFFSETFILE_MAGIC_DATA)-1, out); -+ else -+ fwrite(COLLATIONFILE_MAGIC_DATA, 1, sizeof(COLLATIONFILE_MAGIC_DATA)-1, out); -+ fwrite("url=", 1, sizeof("url=")-1, out); -+ fwrite(url.c_str(), 1, url.length(), out); -+ if (cachefiletype == CacheFileType_clt) { -+#ifdef _MSC_VER -+ fprintf_s(out, "\nfunc=%d", cltfunc); -+#else -+ fprintf(out, "\nfunc=%d", cltfunc); -+#endif -+ } -+ fwrite("\n", 1, 2, out); -+ fwrite(wordoffset, sizeof(guint32), npages, out); -+ fclose(out); -+ g_print("Save cache file: %s\n", cfilename.c_str()); -+ return true; -+ } -+ return false; -+} -+ -+collation_file::collation_file(idxsyn_file *_idx_file, CacheFileType _cachefiletype) : cache_file(_cachefiletype) -+{ -+ idx_file = _idx_file; -+} -+ -+const gchar *collation_file::GetWord(glong idx) -+{ -+ return idx_file->get_key(wordoffset[idx]); -+} -+ -+glong collation_file::GetOrigIndex(glong cltidx) -+{ -+ return wordoffset[cltidx]; -+} -+ -+bool collation_file::lookup(const char *sWord, glong &idx, glong &idx_suggest) -+{ -+ bool bFound=false; -+ glong iTo=idx_file->wordcount-1; -+ if (stardict_collate(sWord, GetWord(0), CollateFunction)<0) { -+ idx = 0; -+ idx_suggest = 0; -+ } else if (stardict_collate(sWord, GetWord(iTo), CollateFunction) >0) { -+ idx = INVALID_INDEX; -+ idx_suggest = iTo; -+ } else { -+ glong iThisIndex=0; -+ glong iFrom=0; -+ gint cmpint; -+ while (iFrom<=iTo) { -+ iThisIndex=(iFrom+iTo)/2; -+ cmpint = stardict_collate(sWord, GetWord(iThisIndex), CollateFunction); -+ if (cmpint>0) -+ iFrom=iThisIndex+1; -+ else if (cmpint<0) -+ iTo=iThisIndex-1; -+ else { -+ bFound=true; -+ break; -+ } -+ } -+ if (!bFound) { -+ idx = iFrom; //next -+ idx_suggest = iFrom; -+ gint best, back; -+ best = prefix_match (sWord, GetWord(idx_suggest)); -+ for (;;) { -+ if ((iTo=idx_suggest-1) < 0) -+ break; -+ back = prefix_match (sWord, GetWord(iTo)); -+ if (!back || back < best) -+ break; -+ best = back; -+ idx_suggest = iTo; -+ } -+ } else { -+ idx = iThisIndex; -+ idx_suggest = iThisIndex; -+ } -+ } -+ return bFound; -+} -+ -+struct sort_collation_index_user_data { -+ idxsyn_file *idx_file; -+ CollateFunctions cltfunc; -+}; -+ -+static gint sort_collation_index(gconstpointer a, gconstpointer b, gpointer user_data) -+{ -+ sort_collation_index_user_data *data = (sort_collation_index_user_data*)user_data; -+ gchar *str1 = g_strdup(data->idx_file->get_key(*((guint32 *)a))); -+ const gchar *str2 = data->idx_file->get_key(*((guint32 *)b)); -+ gint x = stardict_collate(str1, str2, data->cltfunc); -+ g_free(str1); -+ if (x==0) -+ return *((guint32 *)a) - *((guint32 *)b); -+ else -+ return x; -+} -+ -+idxsyn_file::idxsyn_file() -+{ -+ memset(clt_files, 0, sizeof(clt_files)); -+} -+ -+const gchar *idxsyn_file::getWord(glong idx, int EnableCollationLevel, int servercollatefunc) -+{ -+ if (EnableCollationLevel == 0) -+ return get_key(idx); -+ if (EnableCollationLevel == 1) -+ return clt_file->GetWord(idx); -+ if (servercollatefunc == 0) -+ return get_key(idx); -+ collate_load((CollateFunctions)(servercollatefunc-1)); -+ return clt_files[servercollatefunc-1]->GetWord(idx); -+} -+ -+bool idxsyn_file::Lookup(const char *str, glong &idx, glong &idx_suggest, int EnableCollationLevel, int servercollatefunc) -+{ -+ if (EnableCollationLevel == 0) -+ return lookup(str, idx, idx_suggest); -+ if (EnableCollationLevel == 1) -+ return clt_file->lookup(str, idx, idx_suggest); -+ if (servercollatefunc == 0) -+ return lookup(str, idx, idx_suggest); -+ collate_load((CollateFunctions)(servercollatefunc-1)); -+ return clt_files[servercollatefunc-1]->lookup(str, idx, idx_suggest); -+} -+ -+void idxsyn_file::collate_sort(const std::string& url, -+ const std::string& saveurl, -+ CollateFunctions collf, -+ show_progress_t *sp) -+{ -+ clt_file = new collation_file(this, CacheFileType_clt); -+ clt_file->CollateFunction = collf; -+ if (!clt_file->load_cache(url, saveurl, collf, wordcount*sizeof(guint32))) { -+ sp->notify_about_start(_("Sorting, please wait...")); -+ clt_file->wordoffset = (guint32 *)g_malloc(wordcount*sizeof(guint32)); -+ for (glong i=0; i<wordcount; i++) -+ clt_file->wordoffset[i] = i; -+ sort_collation_index_user_data data; -+ data.idx_file = this; -+ data.cltfunc = collf; -+ g_qsort_with_data(clt_file->wordoffset, wordcount, sizeof(guint32), sort_collation_index, &data); -+ if (!clt_file->save_cache(saveurl, collf, wordcount)) -+ g_printerr("Cache update failed.\n"); -+ } -+} -+ -+void idxsyn_file::collate_save_info(const std::string& _url, const std::string& _saveurl) -+{ -+ url = _url; -+ saveurl = _saveurl; -+} -+ -+void idxsyn_file::collate_load(CollateFunctions collf) -+{ -+ if (clt_files[collf]) -+ return; -+ clt_files[collf] = new collation_file(this, CacheFileType_server_clt); -+ clt_files[collf]->CollateFunction = collf; -+ if (!clt_files[collf]->load_cache(url, saveurl, collf, wordcount*sizeof(guint32))) { -+ clt_files[collf]->wordoffset = (guint32 *)g_malloc(wordcount*sizeof(guint32)); -+ for (glong i=0; i<wordcount; i++) -+ clt_files[collf]->wordoffset[i] = i; -+ sort_collation_index_user_data data; -+ data.idx_file = this; -+ data.cltfunc = collf; -+ g_qsort_with_data(clt_files[collf]->wordoffset, wordcount, sizeof(guint32), sort_collation_index, &data); -+ if (!clt_files[collf]->save_cache(saveurl, collf, wordcount)) -+ g_printerr("Cache update failed.\n"); -+ } -+} -+ -+bool offset_index::load(const std::string& url, gulong wc, gulong fsize, -+ bool CreateCacheFile, int EnableCollationLevel, -+ CollateFunctions _CollateFunction, show_progress_t *sp) -+{ -+ wordcount=wc; -+ npages=(wc-1)/ENTR_PER_PAGE+2; -+ if (!oft_file.load_cache(url, url, _CollateFunction, npages*sizeof(guint32))) { -+ MapFile map_file; -+ if (!map_file.open(url.c_str(), fsize)) -+ return false; -+ const gchar *idxdatabuffer=map_file.begin(); -+ oft_file.wordoffset = (guint32 *)g_malloc(npages*sizeof(guint32)); -+ const gchar *p1 = idxdatabuffer; -+ gulong index_size; -+ guint32 j=0; -+ for (guint32 i=0; i<wc; i++) { -+ index_size=strlen(p1) +1 + 2*sizeof(guint32); -+ if (i % ENTR_PER_PAGE==0) { -+ oft_file.wordoffset[j]=p1-idxdatabuffer; -+ ++j; -+ } -+ p1 += index_size; -+ } -+ oft_file.wordoffset[j]=p1-idxdatabuffer; -+ map_file.close(); -+ if (CreateCacheFile) { -+ if (!oft_file.save_cache(url, _CollateFunction, npages)) -+ g_printerr("Cache update failed.\n"); -+ } -+ } -+ -+ if (!(idxfile = fopen(url.c_str(), "rb"))) { -+ return false; -+ } -+ -+ first.assign(0, read_first_on_page_key(0)); -+ last.assign(npages-2, read_first_on_page_key(npages-2)); -+ middle.assign((npages-2)/2, read_first_on_page_key((npages-2)/2)); -+ real_last.assign(wc-1, get_key(wc-1)); -+ -+ if (EnableCollationLevel == 0) { -+ } else if (EnableCollationLevel == 1) { -+ collate_sort(url, url, _CollateFunction, sp); -+ } else if (EnableCollationLevel == 2) { -+ collate_save_info(url, url); -+ } -+ -+ return true; -+} -+ -+inline gulong offset_index::load_page(glong page_idx) -+{ -+ gulong nentr=ENTR_PER_PAGE; -+ if (page_idx==glong(npages-2)) -+ if ((nentr=wordcount%ENTR_PER_PAGE)==0) -+ nentr=ENTR_PER_PAGE; -+ -+ -+ if (page_idx!=page.idx) { -+ page_data.resize(oft_file.wordoffset[page_idx+1]-oft_file.wordoffset[page_idx]); -+ fseek(idxfile, oft_file.wordoffset[page_idx], SEEK_SET); -+ fread(&page_data[0], 1, page_data.size(), idxfile); -+ page.fill(&page_data[0], nentr, page_idx); -+ } -+ -+ return nentr; -+} -+ -+const gchar *offset_index::get_key(glong idx) -+{ -+ load_page(idx/ENTR_PER_PAGE); -+ glong idx_in_page=idx%ENTR_PER_PAGE; -+ wordentry_offset=page.entries[idx_in_page].off; -+ wordentry_size=page.entries[idx_in_page].size; -+ -+ return page.entries[idx_in_page].keystr; -+} -+ -+void offset_index::get_data(glong idx) -+{ -+ get_key(idx); -+} -+ -+const gchar *offset_index::get_key_and_data(glong idx) -+{ -+ return get_key(idx); -+} -+ -+bool offset_index::lookup(const char *str, glong &idx, glong &idx_suggest) -+{ -+ bool bFound=false; -+ glong iFrom; -+ glong iTo=npages-2; -+ gint cmpint; -+ glong iThisIndex; -+ if (stardict_strcmp(str, first.keystr.c_str())<0) { -+ idx = 0; -+ idx_suggest = 0; -+ return false; -+ } else if (stardict_strcmp(str, real_last.keystr.c_str()) >0) { -+ idx = INVALID_INDEX; -+ idx_suggest = iTo; -+ return false; -+ } else { -+ iFrom=0; -+ iThisIndex=0; -+ while (iFrom<=iTo) { -+ iThisIndex=(iFrom+iTo)/2; -+ cmpint = stardict_strcmp(str, get_first_on_page_key(iThisIndex)); -+ if (cmpint>0) -+ iFrom=iThisIndex+1; -+ else if (cmpint<0) -+ iTo=iThisIndex-1; -+ else { -+ bFound=true; -+ break; -+ } -+ } -+ if (!bFound) { -+ idx = iTo; //prev -+ } else { -+ idx = iThisIndex; -+ } -+ } -+ if (!bFound) { -+ gulong netr=load_page(idx); -+ iFrom=1; // Needn't search the first word anymore. -+ iTo=netr-1; -+ iThisIndex=0; -+ while (iFrom<=iTo) { -+ iThisIndex=(iFrom+iTo)/2; -+ cmpint = stardict_strcmp(str, page.entries[iThisIndex].keystr); -+ if (cmpint>0) -+ iFrom=iThisIndex+1; -+ else if (cmpint<0) -+ iTo=iThisIndex-1; -+ else { -+ bFound=true; -+ break; -+ } -+ } -+ idx*=ENTR_PER_PAGE; -+ if (!bFound) { -+ idx += iFrom; //next -+ idx_suggest = idx; -+ gint best, back; -+ best = prefix_match (str, page.entries[idx_suggest % ENTR_PER_PAGE].keystr); -+ for (;;) { -+ if ((iTo=idx_suggest-1) < 0) -+ break; -+ if (idx_suggest % ENTR_PER_PAGE == 0) -+ load_page(iTo / ENTR_PER_PAGE); -+ back = prefix_match (str, page.entries[iTo % ENTR_PER_PAGE].keystr); -+ if (!back || back < best) -+ break; -+ best = back; -+ idx_suggest = iTo; -+ } -+ } else { -+ idx += iThisIndex; -+ idx_suggest = idx; -+ } -+ } else { -+ idx*=ENTR_PER_PAGE; -+ idx_suggest = idx; -+ } -+ return bFound; -+} -+ -+wordlist_index::wordlist_index() -+{ -+ clt_file = NULL; -+ idxdatabuf = NULL; -+} -+ -+wordlist_index::~wordlist_index() -+{ -+ delete clt_file; -+ g_free(idxdatabuf); -+} -+ -+bool wordlist_index::load(const std::string& url, gulong wc, gulong fsize, -+ bool CreateCacheFile, int EnableCollationLevel, -+ CollateFunctions _CollateFunction, show_progress_t *sp) -+{ -+ wordcount=wc; -+ gzFile in = gzopen(url.c_str(), "rb"); -+ if (in == NULL) -+ return false; -+ -+ idxdatabuf = (gchar *)g_malloc(fsize); -+ -+ gulong len = gzread(in, idxdatabuf, fsize); -+ gzclose(in); -+ if (len < 0) -+ return false; -+ -+ if (len != fsize) -+ return false; -+ -+ wordlist.resize(wc+1); -+ gchar *p1 = idxdatabuf; -+ guint32 i; -+ for (i=0; i<wc; i++) { -+ wordlist[i] = p1; -+ p1 += strlen(p1) +1 + 2*sizeof(guint32); -+ } -+ wordlist[wc] = p1; -+ -+ if (EnableCollationLevel == 0) { -+ } else { -+ std::string saveurl = url; -+ saveurl.erase(saveurl.length()-sizeof(".gz")+1, sizeof(".gz")-1); -+ if (EnableCollationLevel == 1) { -+ collate_sort(url, saveurl, _CollateFunction, sp); -+ } else if (EnableCollationLevel == 2) { -+ collate_save_info(url, saveurl); -+ } -+ } -+ return true; -+} -+ -+const gchar *wordlist_index::get_key(glong idx) -+{ -+ return wordlist[idx]; -+} -+ -+void wordlist_index::get_data(glong idx) -+{ -+ gchar *p1 = wordlist[idx]+strlen(wordlist[idx])+sizeof(gchar); -+ wordentry_offset = g_ntohl(get_uint32(p1)); -+ p1 += sizeof(guint32); -+ wordentry_size = g_ntohl(get_uint32(p1)); -+} -+ -+const gchar *wordlist_index::get_key_and_data(glong idx) -+{ -+ get_data(idx); -+ return get_key(idx); -+} -+ -+bool wordlist_index::lookup(const char *str, glong &idx, glong &idx_suggest) -+{ -+ bool bFound=false; -+ glong iTo=wordlist.size()-2; -+ -+ if (stardict_strcmp(str, get_key(0))<0) { -+ idx = 0; -+ idx_suggest = 0; -+ } else if (stardict_strcmp(str, get_key(iTo)) >0) { -+ idx = INVALID_INDEX; -+ idx_suggest = iTo; -+ } else { -+ glong iThisIndex=0; -+ glong iFrom=0; -+ gint cmpint; -+ while (iFrom<=iTo) { -+ iThisIndex=(iFrom+iTo)/2; -+ cmpint = stardict_strcmp(str, get_key(iThisIndex)); -+ if (cmpint>0) -+ iFrom=iThisIndex+1; -+ else if (cmpint<0) -+ iTo=iThisIndex-1; -+ else { -+ bFound=true; -+ break; -+ } -+ } -+ if (!bFound) { -+ idx = iFrom; //next -+ idx_suggest = iFrom; -+ gint best, back; -+ best = prefix_match (str, get_key(idx_suggest)); -+ for (;;) { -+ if ((iTo=idx_suggest-1) < 0) -+ break; -+ back = prefix_match (str, get_key(iTo)); -+ if (!back || back < best) -+ break; -+ best = back; -+ idx_suggest = iTo; -+ } -+ } else { -+ idx = iThisIndex; -+ idx_suggest = iThisIndex; -+ } -+ } -+ return bFound; -+} -+ -+//=================================================================== -+void synonym_file::page_t::fill(gchar *data, gint nent, glong idx_) -+{ -+ idx=idx_; -+ gchar *p=data; -+ glong len; -+ for (gint i=0; i<nent; ++i) { -+ entries[i].keystr=p; -+ len=strlen(p); -+ p+=len+1; -+ entries[i].index=g_ntohl(get_uint32(p)); -+ p+=sizeof(guint32); -+ } -+} -+ -+synonym_file::synonym_file() : oft_file(CacheFileType_oft) -+{ -+ clt_file = NULL; -+} -+ -+synonym_file::~synonym_file() -+{ -+ delete clt_file; -+ if (synfile) -+ fclose(synfile); -+} -+ -+inline const gchar *synonym_file::read_first_on_page_key(glong page_idx) -+{ -+ fseek(synfile, oft_file.wordoffset[page_idx], SEEK_SET); -+ guint32 page_size=oft_file.wordoffset[page_idx+1]-oft_file.wordoffset[page_idx]; -+ gulong minsize = sizeof(wordentry_buf); -+ if (page_size < minsize) -+ minsize = page_size; -+ fread(wordentry_buf, minsize, 1, synfile); //TODO: check returned values, deal with word entry that strlen>255. -+ return wordentry_buf; -+} -+ -+inline const gchar *synonym_file::get_first_on_page_key(glong page_idx) -+{ -+ if (page_idx<middle.idx) { -+ if (page_idx==first.idx) -+ return first.keystr.c_str(); -+ return read_first_on_page_key(page_idx); -+ } else if (page_idx>middle.idx) { -+ if (page_idx==last.idx) -+ return last.keystr.c_str(); -+ return read_first_on_page_key(page_idx); -+ } else -+ return middle.keystr.c_str(); -+} -+ -+bool synonym_file::load(const std::string& url, gulong wc, bool CreateCacheFile, -+ int EnableCollationLevel, CollateFunctions _CollateFunction, -+ show_progress_t *sp) -+{ -+ wordcount=wc; -+ npages=(wc-1)/ENTR_PER_PAGE+2; -+ if (!oft_file.load_cache(url, url, _CollateFunction, npages*sizeof(guint32))) { -+ struct stat stats; -+ if (stat (url.c_str(), &stats) == -1) -+ return false; -+ MapFile map_file; -+ if (!map_file.open(url.c_str(), stats.st_size)) -+ return false; -+ const gchar *syndatabuffer=map_file.begin(); -+ oft_file.wordoffset = (guint32 *)g_malloc(npages*sizeof(guint32)); -+ const gchar *p1 = syndatabuffer; -+ gulong index_size; -+ guint32 j=0; -+ for (guint32 i=0; i<wc; i++) { -+ index_size=strlen(p1) +1 + sizeof(guint32); -+ if (i % ENTR_PER_PAGE==0) { -+ oft_file.wordoffset[j]=p1-syndatabuffer; -+ ++j; -+ } -+ p1 += index_size; -+ } -+ oft_file.wordoffset[j]=p1-syndatabuffer; -+ map_file.close(); -+ if (CreateCacheFile) { -+ if (!oft_file.save_cache(url, _CollateFunction, npages)) -+ g_printerr("Cache update failed.\n"); -+ } -+ } -+ -+ if (!(synfile = fopen(url.c_str(), "rb"))) { -+ return false; -+ } -+ -+ first.assign(0, read_first_on_page_key(0)); -+ last.assign(npages-2, read_first_on_page_key(npages-2)); -+ middle.assign((npages-2)/2, read_first_on_page_key((npages-2)/2)); -+ real_last.assign(wc-1, get_key(wc-1)); -+ -+ if (EnableCollationLevel == 0) { -+ } else if (EnableCollationLevel == 1) -+ collate_sort(url, url, _CollateFunction, sp); -+ else if (EnableCollationLevel == 2) { -+ collate_save_info(url, url); -+ } -+ -+ return true; -+} -+ -+inline gulong synonym_file::load_page(glong page_idx) -+{ -+ gulong nentr=ENTR_PER_PAGE; -+ if (page_idx==glong(npages-2)) -+ if ((nentr=wordcount%ENTR_PER_PAGE)==0) -+ nentr=ENTR_PER_PAGE; -+ -+ -+ if (page_idx!=page.idx) { -+ page_data.resize(oft_file.wordoffset[page_idx+1]-oft_file.wordoffset[page_idx]); -+ fseek(synfile, oft_file.wordoffset[page_idx], SEEK_SET); -+ fread(&page_data[0], 1, page_data.size(), synfile); -+ page.fill(&page_data[0], nentr, page_idx); -+ } -+ -+ return nentr; -+} -+ -+const gchar *synonym_file::get_key(glong idx) -+{ -+ load_page(idx/ENTR_PER_PAGE); -+ glong idx_in_page=idx%ENTR_PER_PAGE; -+ wordentry_index=page.entries[idx_in_page].index; -+ -+ return page.entries[idx_in_page].keystr; -+} -+ -+bool synonym_file::lookup(const char *str, glong &idx, glong &idx_suggest) -+{ -+ bool bFound=false; -+ glong iFrom; -+ glong iTo=npages-2; -+ gint cmpint; -+ glong iThisIndex; -+ if (stardict_strcmp(str, first.keystr.c_str())<0) { -+ idx = 0; -+ idx_suggest = 0; -+ return false; -+ } else if (stardict_strcmp(str, real_last.keystr.c_str()) >0) { -+ idx = INVALID_INDEX; -+ idx_suggest = iTo; -+ return false; -+ } else { -+ iFrom=0; -+ iThisIndex=0; -+ while (iFrom<=iTo) { -+ iThisIndex=(iFrom+iTo)/2; -+ cmpint = stardict_strcmp(str, get_first_on_page_key(iThisIndex)); -+ if (cmpint>0) -+ iFrom=iThisIndex+1; -+ else if (cmpint<0) -+ iTo=iThisIndex-1; -+ else { -+ bFound=true; -+ break; -+ } -+ } -+ if (!bFound) -+ idx = iTo; //prev -+ else -+ idx = iThisIndex; -+ } -+ if (!bFound) { -+ gulong netr=load_page(idx); -+ iFrom=1; // Needn't search the first word anymore. -+ iTo=netr-1; -+ iThisIndex=0; -+ while (iFrom<=iTo) { -+ iThisIndex=(iFrom+iTo)/2; -+ cmpint = stardict_strcmp(str, page.entries[iThisIndex].keystr); -+ if (cmpint>0) -+ iFrom=iThisIndex+1; -+ else if (cmpint<0) -+ iTo=iThisIndex-1; -+ else { -+ bFound=true; -+ break; -+ } -+ } -+ idx*=ENTR_PER_PAGE; -+ if (!bFound) { -+ idx += iFrom; //next -+ idx_suggest = idx; -+ gint best, back; -+ best = prefix_match (str, page.entries[idx_suggest % ENTR_PER_PAGE].keystr); -+ for (;;) { -+ if ((iTo=idx_suggest-1) < 0) -+ break; -+ if (idx_suggest % ENTR_PER_PAGE == 0) -+ load_page(iTo / ENTR_PER_PAGE); -+ back = prefix_match (str, page.entries[iTo % ENTR_PER_PAGE].keystr); -+ if (!back || back < best) -+ break; -+ best = back; -+ idx_suggest = iTo; -+ } -+ } else { -+ idx += iThisIndex; -+ idx_suggest = idx; -+ } -+ } else { -+ idx*=ENTR_PER_PAGE; -+ idx_suggest = idx; -+ } -+ return bFound; -+} -+ -+//=================================================================== -+Dict::Dict() -+{ -+ storage = NULL; -+} -+ -+Dict::~Dict() -+{ -+ delete storage; -+} -+ -+bool Dict::load(const std::string& ifofilename, bool CreateCacheFile, -+ int EnableCollationLevel, CollateFunctions CollateFunction, -+ show_progress_t *sp) -+{ -+ gulong idxfilesize; -+ glong wordcount, synwordcount; -+ if (!load_ifofile(ifofilename, idxfilesize, wordcount, synwordcount)) -+ return false; -+ sp->notify_about_start(_("Loading...")); -+ std::string fullfilename(ifofilename); -+ fullfilename.replace(fullfilename.length()-sizeof("ifo")+1, sizeof("ifo")-1, "dict.dz"); -+ -+ if (g_file_test(fullfilename.c_str(), G_FILE_TEST_EXISTS)) { -+ dictdzfile.reset(new dictData); -+ if (!dictdzfile->open(fullfilename, 0)) { -+ //g_print("open file %s failed!\n",fullfilename); -+ return false; -+ } -+ } else { -+ fullfilename.erase(fullfilename.length()-sizeof(".dz")+1, sizeof(".dz")-1); -+ dictfile = fopen(fullfilename.c_str(),"rb"); -+ if (!dictfile) { -+ //g_print("open file %s failed!\n",fullfilename); -+ return false; -+ } -+ } -+ -+ fullfilename=ifofilename; -+ fullfilename.replace(fullfilename.length()-sizeof("ifo")+1, sizeof("ifo")-1, "idx.gz"); -+ -+ if (g_file_test(fullfilename.c_str(), G_FILE_TEST_EXISTS)) { -+ idx_file.reset(new wordlist_index); -+ } else { -+ fullfilename.erase(fullfilename.length()-sizeof(".gz")+1, sizeof(".gz")-1); -+ idx_file.reset(new offset_index); -+ } -+ -+ if (!idx_file->load(fullfilename, wordcount, idxfilesize, -+ CreateCacheFile, EnableCollationLevel, -+ CollateFunction, sp)) -+ return false; -+ -+ if (synwordcount) { -+ fullfilename=ifofilename; -+ fullfilename.replace(fullfilename.length()-sizeof("ifo")+1, sizeof("ifo")-1, "syn"); -+ if (g_file_test(fullfilename.c_str(), G_FILE_TEST_EXISTS)) { -+ syn_file.reset(new synonym_file); -+ if (!syn_file->load(fullfilename, synwordcount, -+ CreateCacheFile, EnableCollationLevel, -+ CollateFunction, sp)) -+ return false; -+ } -+ } -+ -+ bool has_res = false; -+ gchar *dirname = g_path_get_dirname(ifofilename.c_str()); -+ fullfilename = dirname; -+ fullfilename += G_DIR_SEPARATOR_S "res"; -+ if (g_file_test(fullfilename.c_str(), G_FILE_TEST_IS_DIR)) { -+ has_res = true; -+ } else { -+ fullfilename = dirname; -+ fullfilename += G_DIR_SEPARATOR_S "res.rifo"; -+ if (g_file_test(fullfilename.c_str(), G_FILE_TEST_EXISTS)) { -+ has_res = true; -+ } -+ } -+ if (has_res) { -+ storage = new ResourceStorage(); -+ bool failed = storage->load(dirname); -+ if (failed) { -+ delete storage; -+ storage = NULL; -+ } -+ } -+ g_free(dirname); -+ -+ g_print("bookname: %s , wordcount %lu\n", bookname.c_str(), wordcount); -+ return true; -+} -+ -+bool Dict::load_ifofile(const std::string& ifofilename, gulong &idxfilesize, glong &wordcount, glong &synwordcount) -+{ -+ DictInfo dict_info; -+ if (!dict_info.load_from_ifo_file(ifofilename, false)) -+ return false; -+ if (dict_info.wordcount==0) -+ return false; -+ -+ ifo_file_name=dict_info.ifo_file_name; -+ bookname=dict_info.bookname; -+ -+ idxfilesize=dict_info.index_file_size; -+ wordcount=dict_info.wordcount; -+ synwordcount=dict_info.synwordcount; -+ -+ sametypesequence=dict_info.sametypesequence; -+ dicttype=dict_info.dicttype; -+ -+ return true; -+} -+ -+glong Dict::nsynarticles() -+{ -+ if (syn_file.get() == NULL) -+ return 0; -+ return syn_file->wordcount; -+} -+ -+bool Dict::GetWordPrev(glong idx, glong &pidx, bool isidx, int EnableCollationLevel, int servercollatefunc) -+{ -+ idxsyn_file *is_file; -+ if (isidx) -+ is_file = idx_file.get(); -+ else -+ is_file = syn_file.get(); -+ if (idx==INVALID_INDEX) { -+ pidx = is_file->wordcount-1; -+ return true; -+ } -+ pidx = idx; -+ gchar *cWord = g_strdup(is_file->getWord(pidx, EnableCollationLevel, servercollatefunc)); -+ const gchar *pWord; -+ bool found=false; -+ while (pidx>0) { -+ pWord = is_file->getWord(pidx-1, EnableCollationLevel, servercollatefunc); -+ if (strcmp(pWord, cWord)!=0) { -+ found=true; -+ break; -+ } -+ pidx--; -+ } -+ g_free(cWord); -+ if (found) { -+ pidx--; -+ return true; -+ } else { -+ return false; -+ } -+} -+ -+void Dict::GetWordNext(glong &idx, bool isidx, int EnableCollationLevel, int servercollatefunc) -+{ -+ idxsyn_file *is_file; -+ if (isidx) -+ is_file = idx_file.get(); -+ else -+ is_file = syn_file.get(); -+ gchar *cWord = g_strdup(is_file->getWord(idx, EnableCollationLevel, servercollatefunc)); -+ const gchar *pWord; -+ bool found=false; -+ while (idx < is_file->wordcount-1) { -+ pWord = is_file->getWord(idx+1, EnableCollationLevel, servercollatefunc); -+ if (strcmp(pWord, cWord)!=0) { -+ found=true; -+ break; -+ } -+ idx++; -+ } -+ g_free(cWord); -+ if (found) -+ idx++; -+ else -+ idx=INVALID_INDEX; -+} -+ -+gint Dict::GetOrigWordCount(glong& idx, bool isidx) -+{ -+ idxsyn_file *is_file; -+ if (isidx) -+ is_file = idx_file.get(); -+ else -+ is_file = syn_file.get(); -+ gchar *cWord = g_strdup(is_file->get_key(idx)); -+ const gchar *pWord; -+ gint count = 1; -+ glong idx1 = idx; -+ while (idx1>0) { -+ pWord = is_file->get_key(idx1-1); -+ if (strcmp(pWord, cWord)!=0) -+ break; -+ count++; -+ idx1--; -+ } -+ glong idx2=idx; -+ while (idx2<is_file->wordcount-1) { -+ pWord = is_file->get_key(idx2+1); -+ if (strcmp(pWord, cWord)!=0) -+ break; -+ count++; -+ idx2++; -+ } -+ idx=idx1; -+ g_free(cWord); -+ return count; -+} -+ -+bool Dict::LookupSynonym(const char *str, glong &synidx, glong &synidx_suggest, int EnableCollationLevel, int servercollatefunc) -+{ -+ if (syn_file.get() == NULL) { -+ synidx = UNSET_INDEX; -+ synidx_suggest = UNSET_INDEX; -+ return false; -+ } -+ return syn_file->Lookup(str, synidx, synidx_suggest, EnableCollationLevel, servercollatefunc); -+} -+ -+bool Dict::LookupWithRule(GPatternSpec *pspec, glong *aIndex, int iBuffLen) -+{ -+ int iIndexCount=0; -+ for (glong i=0; i<narticles() && iIndexCount<iBuffLen-1; i++) -+ // Need to deal with same word in index? But this will slow down processing in most case. -+ if (g_pattern_match_string(pspec, idx_file->getWord(i, 0, 0))) -+ aIndex[iIndexCount++]=i; -+ aIndex[iIndexCount]= -1; // -1 is the end. -+ return (iIndexCount>0); -+} -+ -+bool Dict::LookupWithRuleSynonym(GPatternSpec *pspec, glong *aIndex, int iBuffLen) -+{ -+ if (syn_file.get() == NULL) -+ return false; -+ int iIndexCount=0; -+ for (glong i=0; i<nsynarticles() && iIndexCount<iBuffLen-1; i++) -+ // Need to deal with same word in index? But this will slow down processing in most case. -+ if (g_pattern_match_string(pspec, syn_file->getWord(i, 0, 0))) -+ aIndex[iIndexCount++]=i; -+ aIndex[iIndexCount]= -1; // -1 is the end. -+ return (iIndexCount>0); -+} -+ -+bool Dict::LookupWithRegex(GRegex *regex, glong *aIndex, int iBuffLen) -+{ -+ int iIndexCount=0; -+ for (glong i=0; i<narticles() && iIndexCount<iBuffLen-1; i++) -+ // Need to deal with same word in index? But this will slow down processing in most case. -+ if (g_regex_match(regex, idx_file->getWord(i, 0, 0), (GRegexMatchFlags)0, NULL)) -+ aIndex[iIndexCount++]=i; -+ aIndex[iIndexCount]= -1; // -1 is the end. -+ return (iIndexCount>0); -+} -+ -+bool Dict::LookupWithRegexSynonym(GRegex *regex, glong *aIndex, int iBuffLen) -+{ -+ if (syn_file.get() == NULL) -+ return false; -+ int iIndexCount=0; -+ for (glong i=0; i<nsynarticles() && iIndexCount<iBuffLen-1; i++) -+ // Need to deal with same word in index? But this will slow down processing in most case. -+ if (g_regex_match(regex, syn_file->getWord(i, 0, 0), (GRegexMatchFlags)0, NULL)) -+ aIndex[iIndexCount++]=i; -+ aIndex[iIndexCount]= -1; // -1 is the end. -+ return (iIndexCount>0); -+} -+ -+//=================================================================== -+show_progress_t Libs::default_show_progress; -+ -+Libs::Libs(show_progress_t *sp, bool create, int enablelevel, int function) -+{ -+#ifdef SD_SERVER_CODE -+ root_info_item = NULL; -+#endif -+ set_show_progress(sp); -+ CreateCacheFile = create; -+ EnableCollationLevel = enablelevel; -+ CollateFunction = (CollateFunctions)function; -+ iMaxFuzzyDistance = MAX_FUZZY_DISTANCE; //need to read from cfg. -+ if (EnableCollationLevel == 0) { -+ } else if (EnableCollationLevel == 1) { -+ if (utf8_collate_init(CollateFunction)) -+ printf("Init collate function failed!\n"); -+ } else if (EnableCollationLevel == 2){ -+ if (utf8_collate_init_all()) -+ printf("Init collate functions failed!\n"); -+ } -+} -+ -+Libs::~Libs() -+{ -+#ifdef SD_SERVER_CODE -+ if (root_info_item) -+ delete root_info_item; -+#endif -+ for (std::vector<Dict *>::iterator p=oLib.begin(); p!=oLib.end(); ++p) -+ delete *p; -+ utf8_collate_end(); -+} -+ -+bool Libs::load_dict(const std::string& url, show_progress_t *sp) -+{ -+ Dict *lib=new Dict; -+ if (lib->load(url, CreateCacheFile, EnableCollationLevel, -+ CollateFunction, sp)) { -+ oLib.push_back(lib); -+ return true; -+ } else { -+ delete lib; -+ return false; -+ } -+} -+ -+#ifdef SD_SERVER_CODE -+void Libs::LoadFromXML() -+{ -+ root_info_item = new DictInfoItem(); -+ root_info_item->isdir = 1; -+ root_info_item->dir = new DictInfoDirItem(); -+ root_info_item->dir->name='/'; -+ LoadXMLDir("/usr/share/stardict/dic", root_info_item); -+ GenLinkDict(root_info_item); -+} -+ -+void Libs::GenLinkDict(DictInfoItem *info_item) -+{ -+ std::list<std::list<DictInfoItem *>::iterator> eraselist; -+ for (std::list<DictInfoItem *>::iterator i = info_item->dir->info_item_list.begin(); i!= info_item->dir->info_item_list.end(); ++i) { -+ if ((*i)->isdir == 1) { -+ GenLinkDict(*i); -+ } else if ((*i)->isdir == 2) { -+ std::map<std::string, DictInfoDictItem *>::iterator uid_iter; -+ uid_iter = uidmap.find(*((*i)->linkuid)); -+ if (uid_iter!=uidmap.end()) { -+ delete (*i)->linkuid; -+ (*i)->dict = uid_iter->second; -+ } else { -+ g_print("Error, linkdict uid not found! %s\n", (*i)->linkuid->c_str()); -+ delete (*i)->linkuid; -+ eraselist.push_back(i); -+ } -+ } -+ } -+ for (std::list<std::list<DictInfoItem *>::iterator>::iterator i = eraselist.begin(); i!= eraselist.end(); ++i) { -+ info_item->dir->info_item_list.erase(*i); -+ } -+} -+ -+void Libs::func_parse_start_element(GMarkupParseContext *context, const gchar *element_name, const gchar **attribute_names, const gchar **attribute_values, gpointer user_data, GError **error) -+{ -+ if (strcmp(element_name, "dict")==0) { -+ ParseUserData *Data = (ParseUserData *)user_data; -+ Data->indict = true; -+ Data->path.clear(); -+ Data->uid.clear(); -+ Data->level.clear(); -+ Data->download.clear(); -+ Data->from.clear(); -+ Data->to.clear(); -+ } else if (strcmp(element_name, "linkdict")==0) { -+ ParseUserData *Data = (ParseUserData *)user_data; -+ Data->inlinkdict = true; -+ Data->linkuid.clear(); -+ } -+} -+ -+void Libs::func_parse_end_element(GMarkupParseContext *context, const gchar *element_name, gpointer user_data, GError **error) -+{ -+ if (strcmp(element_name, "dict")==0) { -+ ParseUserData *Data = (ParseUserData *)user_data; -+ Data->indict = false; -+ if (!Data->path.empty() && !Data->uid.empty()) { -+ std::string url; -+ url = Data->dir; -+ url += G_DIR_SEPARATOR; -+ url += Data->path; -+ if (Data->oLibs->load_dict(url, Data->oLibs->show_progress)) { -+ DictInfoItem *sub_info_item = new DictInfoItem(); -+ sub_info_item->isdir = 0; -+ sub_info_item->dict = new DictInfoDictItem(); -+ sub_info_item->dict->uid = Data->uid; -+ sub_info_item->dict->download = Data->download; -+ sub_info_item->dict->from = Data->from; -+ sub_info_item->dict->to = Data->to; -+ if (Data->level.empty()) -+ sub_info_item->dict->level = 0; -+ else -+ sub_info_item->dict->level = atoi(Data->level.c_str()); -+ sub_info_item->dict->id = Data->oLibs->oLib.size()-1; -+ Data->info_item->dir->info_item_list.push_back(sub_info_item); -+ Data->oLibs->uidmap[Data->uid] = sub_info_item->dict; -+ } -+ } -+ } else if (strcmp(element_name, "linkdict")==0) { -+ ParseUserData *Data = (ParseUserData *)user_data; -+ Data->inlinkdict = false; -+ if (!Data->linkuid.empty()) { -+ DictInfoItem *sub_info_item = new DictInfoItem(); -+ sub_info_item->isdir = 2; -+ sub_info_item->linkuid = new std::string(Data->linkuid); -+ Data->info_item->dir->info_item_list.push_back(sub_info_item); -+ } -+ } -+} -+ -+void Libs::func_parse_text(GMarkupParseContext *context, const gchar *text, gsize text_len, gpointer user_data, GError **error) -+{ -+ const gchar *element = g_markup_parse_context_get_element(context); -+ if (!element) -+ return; -+ ParseUserData *Data = (ParseUserData *)user_data; -+ if (strcmp(element, "subdir")==0) { -+ std::string subdir; -+ subdir = Data->dir; -+ subdir += G_DIR_SEPARATOR; -+ subdir.append(text, text_len); -+ DictInfoItem *sub_info_item = new DictInfoItem(); -+ sub_info_item->isdir = 1; -+ sub_info_item->dir = new DictInfoDirItem(); -+ sub_info_item->dir->name.assign(text, text_len); -+ Data->oLibs->LoadXMLDir(subdir.c_str(), sub_info_item); -+ Data->info_item->dir->info_item_list.push_back(sub_info_item); -+ } else if (strcmp(element, "dirname")==0) { -+ Data->info_item->dir->dirname.assign(text, text_len); -+ } else if (strcmp(element, "path")==0) { -+ Data->path.assign(text, text_len); -+ } else if (strcmp(element, "uid")==0) { -+ if (Data->indict) { -+ std::string uid(text, text_len); -+ if (uid.find_first_of(' ')!=std::string::npos) { -+ g_print("Error: uid contains space! %s: %s\n", Data->dir, uid.c_str()); -+ } else { -+ std::map<std::string, DictInfoDictItem *>::iterator uid_iter; -+ uid_iter = Data->oLibs->uidmap.find(uid); -+ if (uid_iter!=Data->oLibs->uidmap.end()) { -+ g_print("Error: uid duplicated! %s: %s\n", Data->dir, uid.c_str()); -+ } else { -+ Data->uid = uid; -+ } -+ } -+ } else if (Data->inlinkdict) { -+ Data->linkuid.assign(text, text_len); -+ } -+ } else if (strcmp(element, "level")==0) { -+ Data->level.assign(text, text_len); -+ } else if (strcmp(element, "download")==0) { -+ Data->download.assign(text, text_len); -+ } else if (strcmp(element, "from")==0) { -+ Data->from.assign(text, text_len); -+ } else if (strcmp(element, "to")==0) { -+ Data->to.assign(text, text_len); -+ } -+} -+ -+void Libs::LoadXMLDir(const char *dir, DictInfoItem *info_item) -+{ -+ std::string filename; -+ filename = dir; -+ filename += G_DIR_SEPARATOR_S "stardictd.xml"; -+ struct stat filestat; -+ if (g_stat(filename.c_str(), &filestat)!=0) -+ return; -+ MapFile mf; -+ if (!mf.open(filename.c_str(), filestat.st_size)) -+ return; -+ ParseUserData Data; -+ Data.oLibs = this; -+ Data.dir = dir; -+ Data.info_item = info_item; -+ Data.indict = false; -+ Data.inlinkdict = false; -+ GMarkupParser parser; -+ parser.start_element = func_parse_start_element; -+ parser.end_element = func_parse_end_element; -+ parser.text = func_parse_text; -+ parser.passthrough = NULL; -+ parser.error = NULL; -+ GMarkupParseContext* context = g_markup_parse_context_new(&parser, (GMarkupParseFlags)0, &Data, NULL); -+ g_markup_parse_context_parse(context, mf.begin(), filestat.st_size, NULL); -+ g_markup_parse_context_end_parse(context, NULL); -+ g_markup_parse_context_free(context); -+ mf.close(); -+ info_item->dir->dictcount = 0; -+ for (std::list<DictInfoItem *>::iterator i = info_item->dir->info_item_list.begin(); i!= info_item->dir->info_item_list.end(); ++i) { -+ if ((*i)->isdir == 1) { -+ info_item->dir->dictcount += (*i)->dir->dictcount; -+ } else if ((*i)->isdir == 0) { -+ info_item->dir->dictcount++; -+ } -+ } -+} -+ -+const std::string &Libs::get_fromto_info() { -+ if(cache_fromto.empty()){ -+ std::map<std::string, std::list<FromTo> > map_fromto; -+ gen_fromto_info(root_info_item, map_fromto); -+ cache_fromto+="<lang>"; -+ for (std::map<std::string, std::list<FromTo> >::iterator map_it = map_fromto.begin(); map_it != map_fromto.end(); ++map_it){ -+ cache_fromto+="<from lang=\""; -+ cache_fromto+=map_it->first; -+ cache_fromto+="\">"; -+ std::list<FromTo> &fromTo = map_it->second; -+ for (std::list<FromTo>::iterator i = fromTo.begin() ; i!= fromTo.end(); ++i){ -+ cache_fromto+="<to lang=\""; -+ cache_fromto+= i->to; -+ cache_fromto+="\">"; -+ std::list<FromToInfo> &fromtoinfo = i->fromto_info; -+ for (std::list<FromToInfo>::iterator j = fromtoinfo.begin() ; j!= fromtoinfo.end(); ++j){ -+ cache_fromto+="<dict><uid>"; -+ cache_fromto+=j->uid; -+ cache_fromto+="</uid><bookname>"; -+ cache_fromto+= j->bookname; -+ cache_fromto+="</bookname></dict>"; -+ } -+ cache_fromto+="</to>"; -+ } -+ cache_fromto+="</from>"; -+ } -+ cache_fromto+="</lang>"; -+ } -+ return cache_fromto; -+} -+ -+void Libs::gen_fromto_info(struct DictInfoItem *info_item, std::map<std::string, std::list<FromTo> > &map_fromto) { -+ gchar *etext; -+ for(std::list<DictInfoItem *>::iterator i = info_item->dir->info_item_list.begin() ; i!= info_item->dir->info_item_list.end(); ++i){ -+ if ((*i)->isdir == 1) { -+ gen_fromto_info((*i), map_fromto); -+ } else { -+ std::string from_str = (*i)->dict->from; -+ std::string to_str = (*i)->dict->to; -+ if(from_str.empty() || to_str.empty()){ -+ continue; -+ } -+ std::string uid_str = (*i)->dict->uid; -+ etext = g_markup_escape_text(oLib[(*i)->dict->id]->dict_name().c_str(), -1); -+ std::string bookname_str = etext; -+ g_free(etext); -+ std::map<std::string, std::list<FromTo> >::iterator fromto1 = map_fromto.find(from_str); -+ if (fromto1==map_fromto.end()) { -+ //if an from_str element not already in map, add new from_str to map -+ FromToInfo fromtoinfo; -+ fromtoinfo.uid = uid_str; -+ fromtoinfo.bookname = bookname_str; -+ std::list<FromToInfo> list_fromtoinfo ; -+ list_fromtoinfo.push_back(fromtoinfo); -+ FromTo new_fromTo; -+ new_fromTo.to = to_str; -+ new_fromTo.fromto_info = list_fromtoinfo; -+ std::list<FromTo> list_fromTo; -+ list_fromTo.push_back(new_fromTo); -+ map_fromto[from_str] = list_fromTo; -+ } else { -+ // else if from_str already in map, so comparison to_str and from_to1 , then choose insert. -+ std::list<FromTo> &fromTo_list = fromto1->second; -+ std::string from_name1 = fromto1->first; -+ bool found = false; -+ for (std::list<FromTo>::iterator new_fromTo = fromTo_list.begin(); new_fromTo != fromTo_list.end(); ++new_fromTo) { -+ if(to_str == new_fromTo->to) { -+ std::list<FromToInfo> &fromtoinfo1 = new_fromTo->fromto_info; -+ FromToInfo fromtoinfo; -+ fromtoinfo.uid = uid_str; -+ fromtoinfo.bookname = bookname_str; -+ fromtoinfo1.push_back(fromtoinfo); -+ found = true; -+ break; -+ } -+ } -+ if(!found){ -+ FromToInfo fromtoinfo; -+ fromtoinfo.uid = uid_str; -+ fromtoinfo.bookname = bookname_str; -+ std::list<FromToInfo> fromtoinfo1; -+ fromtoinfo1.push_back(fromtoinfo); -+ FromTo fromTo; -+ fromTo.to = to_str; -+ fromTo.fromto_info = fromtoinfo1; -+ fromTo_list.push_back(fromTo); -+ } -+ } -+ } -+ } -+} -+ -+const std::string *Libs::get_dir_info(const char *path) -+{ -+ if (path[0]!='/') -+ return NULL; -+ DictInfoItem *info_item = root_info_item; -+ std::string item; -+ const char *p = path+1; -+ const char *p1; -+ bool found; -+ do { -+ p1 = strchr(p, '/'); -+ if (p1) { -+ item.assign(p, p1-p); -+ if (!item.empty()) { -+ found = false; -+ for (std::list<DictInfoItem *>::iterator i = info_item->dir->info_item_list.begin(); i!= info_item->dir->info_item_list.end(); ++i) { -+ if ((*i)->isdir == 1) { -+ if ((*i)->dir->name == item) { -+ info_item = (*i); -+ found = true; -+ break; -+ } -+ } -+ } -+ if (!found) -+ return NULL; -+ } -+ p = p1+1; -+ } -+ } while (p1); -+ if (*p) -+ return NULL; // Not end by '/'. -+ DictInfoDirItem *dir = info_item->dir; -+ if (dir->info_string.empty()) { -+ dir->info_string += "<parent>"; -+ dir->info_string += path; -+ dir->info_string += "</parent>"; -+ gchar *etext; -+ for (std::list<DictInfoItem *>::iterator i = info_item->dir->info_item_list.begin(); i!= info_item->dir->info_item_list.end(); ++i) { -+ if ((*i)->isdir == 1) { -+ dir->info_string += "<dir><name>"; -+ dir->info_string += (*i)->dir->name; -+ dir->info_string += "</name><dirname>"; -+ dir->info_string += (*i)->dir->dirname; -+ dir->info_string += "</dirname><dictcount>"; -+ gchar *dictcount = g_strdup_printf("%u", (*i)->dir->dictcount); -+ dir->info_string += dictcount; -+ g_free(dictcount); -+ dir->info_string += "</dictcount></dir>"; -+ } else { -+ dir->info_string += "<dict>"; -+ if ((*i)->isdir == 2) -+ dir->info_string += "<islink>1</islink>"; -+ if ((*i)->dict->level != 0) { -+ dir->info_string += "<level>"; -+ gchar *level = g_strdup_printf("%u", (*i)->dict->level); -+ dir->info_string += level; -+ g_free(level); -+ dir->info_string += "</level>"; -+ } -+ dir->info_string += "<uid>"; -+ dir->info_string += (*i)->dict->uid; -+ dir->info_string += "</uid><bookname>"; -+ etext = g_markup_escape_text(oLib[(*i)->dict->id]->dict_name().c_str(), -1); -+ dir->info_string += etext; -+ g_free(etext); -+ dir->info_string += "</bookname><wordcount>"; -+ gchar *wc = g_strdup_printf("%ld", oLib[(*i)->dict->id]->narticles()); -+ dir->info_string += wc; -+ g_free(wc); -+ dir->info_string += "</wordcount></dict>"; -+ } -+ } -+ } -+ return &(dir->info_string); -+} -+ -+int Libs::get_dict_level(const char *uid) -+{ -+ std::map<std::string, DictInfoDictItem *>::iterator uid_iter; -+ uid_iter = uidmap.find(uid); -+ if (uid_iter==uidmap.end()) -+ return -1; -+ return uid_iter->second->level; -+} -+ -+std::string Libs::get_dicts_list(const char *dictmask, int max_dict_count, int userLevel) -+{ -+ std::list<std::string> uid_list; -+ std::string uid; -+ const char *p, *p1; -+ p = dictmask; -+ do { -+ p1 = strchr(p, ' '); -+ if (p1) { -+ uid.assign(p, p1-p); -+ if (!uid.empty()) -+ uid_list.push_back(uid); -+ p = p1+1; -+ } -+ } while (p1); -+ uid = p; -+ if (!uid.empty()) -+ uid_list.push_back(uid); -+ -+ std::string dictmask_str; -+ int count = 0; -+ const std::string *info_string; -+ int level; -+ for (std::list<std::string>::iterator i = uid_list.begin(); i!= uid_list.end(); ++i) { -+ level = get_dict_level((*i).c_str()); -+ if (level < 0 || level > userLevel) -+ continue; -+ info_string = get_dict_info(i->c_str(), true); -+ if (info_string) { -+ if (count>=max_dict_count) -+ break; -+ dictmask_str += info_string->c_str(); -+ count++; -+ } -+ } -+ return dictmask_str; -+} -+ -+const std::string *Libs::get_dict_info(const char *uid, bool is_short) -+{ -+ std::map<std::string, DictInfoDictItem *>::iterator uid_iter; -+ uid_iter = uidmap.find(uid); -+ if (uid_iter==uidmap.end()) -+ return NULL; -+ DictInfoDictItem *dict; -+ dict = uid_iter->second; -+ if (is_short) { -+ if (dict->short_info_string.empty()) { -+ gchar *etext; -+ dict->short_info_string += "<dict><uid>"; -+ dict->short_info_string += uid; -+ dict->short_info_string += "</uid><bookname>"; -+ etext = g_markup_escape_text(oLib[dict->id]->dict_name().c_str(), -1); -+ dict->short_info_string += etext; -+ g_free(etext); -+ dict->short_info_string += "</bookname><wordcount>"; -+ gchar *wc = g_strdup_printf("%ld", oLib[dict->id]->narticles()); -+ dict->short_info_string += wc; -+ g_free(wc); -+ dict->short_info_string += "</wordcount></dict>"; -+ } -+ return &(dict->short_info_string); -+ } else { -+ if (dict->info_string.empty()) { -+ gchar *etext; -+ DictInfo dict_info; -+ if (!dict_info.load_from_ifo_file(oLib[dict->id]->ifofilename(), false)) -+ return NULL; -+ dict->info_string += "<dictinfo><bookname>"; -+ etext = g_markup_escape_text(dict_info.bookname.c_str(), -1); -+ dict->info_string += etext; -+ g_free(etext); -+ dict->info_string += "</bookname><wordcount>"; -+ gchar *wc = g_strdup_printf("%u", dict_info.wordcount); -+ dict->info_string += wc; -+ g_free(wc); -+ dict->info_string += "</wordcount>"; -+ if (dict_info.synwordcount!=0) { -+ dict->info_string += "<synwordcount>"; -+ wc = g_strdup_printf("%u", dict_info.synwordcount); -+ dict->info_string += wc; -+ g_free(wc); -+ dict->info_string += "</synwordcount>"; -+ } -+ dict->info_string += "<author>"; -+ etext = g_markup_escape_text(dict_info.author.c_str(), -1); -+ dict->info_string += etext; -+ g_free(etext); -+ dict->info_string += "</author><email>"; -+ etext = g_markup_escape_text(dict_info.email.c_str(), -1); -+ dict->info_string += etext; -+ g_free(etext); -+ dict->info_string += "</email><website>"; -+ etext = g_markup_escape_text(dict_info.website.c_str(), -1); -+ dict->info_string += etext; -+ g_free(etext); -+ dict->info_string += "</website><description>"; -+ etext = g_markup_escape_text(dict_info.description.c_str(), -1); -+ dict->info_string += etext; -+ g_free(etext); -+ dict->info_string += "</description><date>"; -+ etext = g_markup_escape_text(dict_info.date.c_str(), -1); -+ dict->info_string += etext; -+ g_free(etext); -+ dict->info_string += "</date><download>"; -+ etext = g_markup_escape_text(dict->download.c_str(), -1); -+ dict->info_string += etext; -+ g_free(etext); -+ dict->info_string += "</download></dictinfo>"; -+ } -+ return &(dict->info_string); -+ } -+} -+ -+void Libs::SetServerDictMask(std::vector<InstantDictIndex> &dictmask, const char *dicts, int max, int userLevel) -+{ -+ InstantDictIndex instance_dict_index; -+ instance_dict_index.type = InstantDictType_LOCAL; -+ dictmask.clear(); -+ std::list<std::string> uid_list; -+ std::string uid; -+ const char *p, *p1; -+ p = dicts; -+ do { -+ p1 = strchr(p, ' '); -+ if (p1) { -+ uid.assign(p, p1-p); -+ if (!uid.empty()) -+ uid_list.push_back(uid); -+ p = p1+1; -+ } -+ } while (p1); -+ uid = p; -+ if (!uid.empty()) -+ uid_list.push_back(uid); -+ int count = 0; -+ std::map<std::string, DictInfoDictItem *>::iterator uid_iter; -+ for (std::list<std::string>::iterator i = uid_list.begin(); i!= uid_list.end(); ++i) { -+ uid_iter = uidmap.find(*i); -+ if (uid_iter!=uidmap.end()) { -+ if (max>=0 && count >= max) -+ break; -+ if (userLevel>=0 && (unsigned int)userLevel< uid_iter->second->level) -+ continue; -+ instance_dict_index.index = uid_iter->second->id; -+ dictmask.push_back(instance_dict_index); -+ count++; -+ } -+ } -+} -+ -+void Libs::LoadCollateFile(std::vector<InstantDictIndex> &dictmask, CollateFunctions cltfuc) -+{ -+ for (std::vector<InstantDictIndex>::iterator i = dictmask.begin(); i!=dictmask.end(); ++i) { -+ if ((*i).type == InstantDictType_LOCAL) { -+ oLib[(*i).index]->idx_file->collate_load(cltfuc); -+ if (oLib[(*i).index]->syn_file.get() != NULL) -+ oLib[(*i).index]->syn_file->collate_load(cltfuc); -+ } -+ } -+} -+#endif -+ -+#ifdef SD_CLIENT_CODE -+bool Libs::find_lib_by_filename(const char *filename, size_t &iLib) -+{ -+ for (std::vector<Dict *>::size_type i =0; i < oLib.size(); i++) { -+ if (oLib[i]->ifofilename() == filename) { -+ iLib = i; -+ return true; -+ } -+ } -+ return false; -+} -+ -+void Libs::load(std::list<std::string> &load_list) -+{ -+ for (std::list<std::string>::iterator i = load_list.begin(); i != load_list.end(); ++i) { -+ load_dict(*i, show_progress); -+ } -+} -+ -+void Libs::reload(std::list<std::string> &load_list, int is_coll_enb, int collf) -+{ -+ if (is_coll_enb == EnableCollationLevel && collf == CollateFunction) { -+ std::vector<Dict *> prev(oLib); -+ oLib.clear(); -+ for (std::list<std::string>::iterator i = load_list.begin(); i != load_list.end(); ++i) { -+ std::vector<Dict *>::iterator it; -+ for (it=prev.begin(); it!=prev.end(); ++it) { -+ if ((*it)->ifofilename()==*i) -+ break; -+ } -+ if (it==prev.end()) { -+ load_dict(*i, show_progress); -+ } else { -+ Dict *res=*it; -+ prev.erase(it); -+ oLib.push_back(res); -+ } -+ } -+ for (std::vector<Dict *>::iterator it=prev.begin(); it!=prev.end(); ++it) { -+ delete *it; -+ } -+ } else { -+ for (std::vector<Dict *>::iterator it = oLib.begin(); it != oLib.end(); ++it) -+ delete *it; -+ oLib.clear(); -+ EnableCollationLevel = is_coll_enb; -+ CollateFunction = CollateFunctions(collf); -+ if (EnableCollationLevel == 0) { -+ } else if (EnableCollationLevel == 1) { -+ if (utf8_collate_init(CollateFunction)) -+ printf("Init collate function failed!\n"); -+ } else if (EnableCollationLevel == 2) { -+ if (utf8_collate_init_all()) -+ printf("Init collate functions failed!\n"); -+ } -+ load(load_list); -+ } -+} -+#endif -+ -+glong Libs::CltIndexToOrig(glong cltidx, size_t iLib, int servercollatefunc) -+{ -+ if (EnableCollationLevel == 0) -+ return cltidx; -+ if (EnableCollationLevel == 1) { -+ if (cltidx == INVALID_INDEX) -+ return cltidx; -+ return oLib[iLib]->idx_file->clt_file->GetOrigIndex(cltidx); -+ } -+ if (servercollatefunc == 0) -+ return cltidx; -+ if (cltidx == INVALID_INDEX) -+ return cltidx; -+ oLib[iLib]->idx_file->collate_load((CollateFunctions)(servercollatefunc-1)); -+ return oLib[iLib]->idx_file->clt_files[servercollatefunc-1]->GetOrigIndex(cltidx); -+} -+ -+glong Libs::CltSynIndexToOrig(glong cltidx, size_t iLib, int servercollatefunc) -+{ -+ if (EnableCollationLevel == 0) -+ return cltidx; -+ if (EnableCollationLevel == 1) { -+ if (cltidx == UNSET_INDEX || cltidx == INVALID_INDEX) -+ return cltidx; -+ return oLib[iLib]->syn_file->clt_file->GetOrigIndex(cltidx); -+ } -+ if (servercollatefunc == 0) -+ return cltidx; -+ if (cltidx == UNSET_INDEX || cltidx == INVALID_INDEX) -+ return cltidx; -+ oLib[iLib]->syn_file->collate_load((CollateFunctions)(servercollatefunc-1)); -+ return oLib[iLib]->syn_file->clt_files[servercollatefunc-1]->GetOrigIndex(cltidx); -+} -+ -+const gchar *Libs::GetSuggestWord(const gchar *sWord, CurrentIndex *iCurrent, std::vector<InstantDictIndex> &dictmask, int servercollatefunc) -+{ -+ const gchar *poCurrentWord = NULL; -+ const gchar *word; -+ gint best =0; -+ gint back; -+ std::vector<InstantDictIndex>::size_type iLib; -+ std::vector<Dict *>::size_type iRealLib; -+ for (iLib=0; iLib < dictmask.size(); iLib++) { -+ if (dictmask[iLib].type != InstantDictType_LOCAL) -+ continue; -+ iRealLib = dictmask[iLib].index; -+ if ( poCurrentWord == NULL ) { -+ poCurrentWord = poGetWord(iCurrent[iLib].idx_suggest, iRealLib, servercollatefunc); -+ best = prefix_match (sWord, poCurrentWord); -+ } else { -+ word = poGetWord(iCurrent[iLib].idx_suggest, iRealLib, servercollatefunc); -+ back = prefix_match (sWord, word); -+ if (back > best) { -+ best = back; -+ poCurrentWord = word; -+ } else if (back == best) { -+ gint x = stardict_server_collate(poCurrentWord, word, EnableCollationLevel, CollateFunction, servercollatefunc); -+ if (x > 0) { -+ poCurrentWord = word; -+ } -+ } -+ } -+ } -+ for (iLib=0; iLib<dictmask.size(); iLib++) { -+ if (dictmask[iLib].type != InstantDictType_LOCAL) -+ continue; -+ if (iCurrent[iLib].synidx_suggest==UNSET_INDEX) -+ continue; -+ iRealLib = dictmask[iLib].index; -+ if ( poCurrentWord == NULL ) { -+ poCurrentWord = poGetSynonymWord(iCurrent[iLib].synidx_suggest, iRealLib, servercollatefunc); -+ best = prefix_match (sWord, poCurrentWord); -+ } else { -+ word = poGetSynonymWord(iCurrent[iLib].synidx_suggest, iRealLib, servercollatefunc); -+ back = prefix_match (sWord, word); -+ if (back > best) { -+ best = back; -+ poCurrentWord = word; -+ } else if (back == best) { -+ gint x = stardict_server_collate(poCurrentWord, word, EnableCollationLevel, CollateFunction, servercollatefunc); -+ if (x > 0) { -+ poCurrentWord = word; -+ } -+ } -+ } -+ } -+ return poCurrentWord; -+} -+ -+const gchar *Libs::poGetCurrentWord(CurrentIndex * iCurrent, std::vector<InstantDictIndex> &dictmask, int servercollatefunc) -+{ -+ const gchar *poCurrentWord = NULL; -+ const gchar *word; -+ std::vector<InstantDictIndex>::size_type iLib; -+ std::vector<Dict *>::size_type iRealLib; -+ for (iLib=0; iLib < dictmask.size(); iLib++) { -+ if (dictmask[iLib].type != InstantDictType_LOCAL) -+ continue; -+ iRealLib = dictmask[iLib].index; -+ if (iCurrent[iLib].idx==INVALID_INDEX) -+ continue; -+ if ( iCurrent[iLib].idx>=narticles(iRealLib) || iCurrent[iLib].idx<0) -+ continue; -+ if ( poCurrentWord == NULL ) { -+ poCurrentWord = poGetWord(iCurrent[iLib].idx, iRealLib, servercollatefunc); -+ } else { -+ word = poGetWord(iCurrent[iLib].idx, iRealLib, servercollatefunc); -+ gint x = stardict_server_collate(poCurrentWord, word, EnableCollationLevel, CollateFunction, servercollatefunc); -+ if (x > 0) { -+ poCurrentWord = word; -+ } -+ } -+ } -+ for (iLib=0; iLib<dictmask.size(); iLib++) { -+ if (dictmask[iLib].type != InstantDictType_LOCAL) -+ continue; -+ iRealLib = dictmask[iLib].index; -+ if (iCurrent[iLib].synidx==UNSET_INDEX) -+ continue; -+ if (iCurrent[iLib].synidx==INVALID_INDEX) -+ continue; -+ if ( iCurrent[iLib].synidx>=nsynarticles(iRealLib) || iCurrent[iLib].synidx<0) -+ continue; -+ if ( poCurrentWord == NULL ) { -+ poCurrentWord = poGetSynonymWord(iCurrent[iLib].synidx, iRealLib, servercollatefunc); -+ } else { -+ word = poGetSynonymWord(iCurrent[iLib].synidx, iRealLib, servercollatefunc); -+ gint x = stardict_server_collate(poCurrentWord, word, EnableCollationLevel, CollateFunction, servercollatefunc); -+ if (x > 0) { -+ poCurrentWord = word; -+ } -+ } -+ } -+ return poCurrentWord; -+} -+ -+const gchar * -+Libs::poGetNextWord(const gchar *sWord, CurrentIndex *iCurrent, std::vector<InstantDictIndex> &dictmask, int servercollatefunc) -+{ -+ // the input can be: -+ // (word,iCurrent),read word,write iNext to iCurrent,and return next word. used by TopWin::NextCallback(); -+ // (NULL,iCurrent),read iCurrent,write iNext to iCurrent,and return next word. used by AppCore::ListWords(); -+ const gchar *poCurrentWord = NULL; -+ std::vector<Dict *>::size_type iCurrentLib=0, iCurrentRealLib=0; -+ bool isLib = false; -+ const gchar *word; -+ -+ std::vector<InstantDictIndex>::size_type iLib; -+ std::vector<Dict *>::size_type iRealLib; -+ for (iLib=0; iLib < dictmask.size(); iLib++) { -+ if (dictmask[iLib].type != InstantDictType_LOCAL) -+ continue; -+ iRealLib = dictmask[iLib].index; -+ if (sWord) { -+ oLib[iRealLib]->Lookup(sWord, iCurrent[iLib].idx, iCurrent[iLib].idx_suggest, EnableCollationLevel, servercollatefunc); -+ } -+ if (iCurrent[iLib].idx==INVALID_INDEX) -+ continue; -+ if (iCurrent[iLib].idx>=narticles(iRealLib) || iCurrent[iLib].idx<0) -+ continue; -+ if (poCurrentWord == NULL ) { -+ poCurrentWord = poGetWord(iCurrent[iLib].idx, iRealLib, servercollatefunc); -+ iCurrentLib = iLib; -+ iCurrentRealLib = iRealLib; -+ isLib=true; -+ } else { -+ gint x; -+ word = poGetWord(iCurrent[iLib].idx, iRealLib, servercollatefunc); -+ x = stardict_server_collate(poCurrentWord, word, EnableCollationLevel, CollateFunction, servercollatefunc); -+ if (x > 0) { -+ poCurrentWord = word; -+ iCurrentLib = iLib; -+ iCurrentRealLib = iRealLib; -+ isLib=true; -+ } -+ } -+ } -+ for (iLib=0; iLib < dictmask.size(); iLib++) { -+ if (dictmask[iLib].type != InstantDictType_LOCAL) -+ continue; -+ iRealLib = dictmask[iLib].index; -+ if (sWord) { -+ oLib[iRealLib]->LookupSynonym(sWord, iCurrent[iLib].synidx, iCurrent[iLib].synidx_suggest, EnableCollationLevel, servercollatefunc); -+ } -+ if (iCurrent[iLib].synidx==UNSET_INDEX) -+ continue; -+ if (iCurrent[iLib].synidx==INVALID_INDEX) -+ continue; -+ if (iCurrent[iLib].synidx>=nsynarticles(iRealLib) || iCurrent[iLib].synidx<0) -+ continue; -+ if (poCurrentWord == NULL ) { -+ poCurrentWord = poGetSynonymWord(iCurrent[iLib].synidx, iRealLib, servercollatefunc); -+ iCurrentLib = iLib; -+ iCurrentRealLib = iRealLib; -+ isLib=false; -+ } else { -+ gint x; -+ word = poGetSynonymWord(iCurrent[iLib].synidx, iRealLib, servercollatefunc); -+ x = stardict_server_collate(poCurrentWord, word, EnableCollationLevel, CollateFunction, servercollatefunc); -+ if (x > 0 ) { -+ poCurrentWord = word; -+ iCurrentLib = iLib; -+ iCurrentRealLib = iRealLib; -+ isLib=false; -+ } -+ } -+ } -+ if (poCurrentWord) { -+ for (iLib=0; iLib < dictmask.size(); iLib++) { -+ if (dictmask[iLib].type != InstantDictType_LOCAL) -+ continue; -+ iRealLib = dictmask[iLib].index; -+ if (isLib && (iLib == iCurrentLib)) -+ continue; -+ if (iCurrent[iLib].idx==INVALID_INDEX) -+ continue; -+ if (iCurrent[iLib].idx>=narticles(iRealLib) || iCurrent[iLib].idx<0) -+ continue; -+ word = poGetWord(iCurrent[iLib].idx, iRealLib, servercollatefunc); -+ if (strcmp(poCurrentWord, word) == 0) { -+ GetWordNext(iCurrent[iLib].idx, iRealLib, true, servercollatefunc); -+ } -+ } -+ for (iLib=0; iLib < dictmask.size(); iLib++) { -+ if (dictmask[iLib].type != InstantDictType_LOCAL) -+ continue; -+ iRealLib = dictmask[iLib].index; -+ if ((!isLib) && (iLib == iCurrentLib)) -+ continue; -+ if (iCurrent[iLib].synidx==UNSET_INDEX) -+ continue; -+ if (iCurrent[iLib].synidx==INVALID_INDEX) -+ continue; -+ if (iCurrent[iLib].synidx>=nsynarticles(iRealLib) || iCurrent[iLib].synidx<0) -+ continue; -+ word = poGetSynonymWord(iCurrent[iLib].synidx, iRealLib, servercollatefunc); -+ if (strcmp(poCurrentWord, word) == 0) { -+ GetWordNext(iCurrent[iLib].synidx, iRealLib, false, servercollatefunc); -+ } -+ } -+ //GetWordNext will change poCurrentWord's content, so do it at the last. -+ if (isLib) { -+ GetWordNext(iCurrent[iCurrentLib].idx, iCurrentRealLib, true, servercollatefunc); -+ } else { -+ GetWordNext(iCurrent[iCurrentLib].synidx, iCurrentRealLib, false, servercollatefunc); -+ } -+ poCurrentWord = poGetCurrentWord(iCurrent, dictmask, servercollatefunc); -+ } -+ return poCurrentWord; -+} -+ -+const gchar * -+Libs::poGetPreWord(const gchar *sWord, CurrentIndex* iCurrent, std::vector<InstantDictIndex> &dictmask, int servercollatefunc) -+{ -+ // used by TopWin::PreviousCallback(); the iCurrent is cached by AppCore::TopWinWordChange(); -+ const gchar *poCurrentWord = NULL; -+ std::vector<Dict *>::size_type iCurrentLib=0, iCurrentRealLib=0; -+ bool isLib = false; -+ -+ const gchar *word; -+ glong pidx; -+ std::vector<InstantDictIndex>::size_type iLib; -+ std::vector<Dict *>::size_type iRealLib; -+ for (iLib=0;iLib<dictmask.size();iLib++) { -+ if (dictmask[iLib].type != InstantDictType_LOCAL) -+ continue; -+ iRealLib = dictmask[iLib].index; -+ if (sWord) { -+ oLib[iRealLib]->Lookup(sWord, iCurrent[iLib].idx, iCurrent[iLib].idx_suggest, EnableCollationLevel, servercollatefunc); -+ } -+ if (iCurrent[iLib].idx!=INVALID_INDEX) { -+ if ( iCurrent[iLib].idx>=narticles(iRealLib) || iCurrent[iLib].idx<=0) -+ continue; -+ } -+ if ( poCurrentWord == NULL ) { -+ if (GetWordPrev(iCurrent[iLib].idx, pidx, iRealLib, true, servercollatefunc)) { -+ poCurrentWord = poGetWord(pidx, iRealLib, servercollatefunc); -+ iCurrentLib = iLib; -+ iCurrentRealLib = iRealLib; -+ isLib=true; -+ } -+ } else { -+ if (GetWordPrev(iCurrent[iLib].idx, pidx, iRealLib, true, servercollatefunc)) { -+ gint x; -+ word = poGetWord(pidx, iRealLib, servercollatefunc); -+ x = stardict_server_collate(poCurrentWord, word, EnableCollationLevel, CollateFunction, servercollatefunc); -+ if (x < 0 ) { -+ poCurrentWord = word; -+ iCurrentLib = iLib; -+ iCurrentRealLib = iRealLib; -+ isLib=true; -+ } -+ } -+ } -+ } -+ for (iLib=0;iLib<dictmask.size();iLib++) { -+ if (dictmask[iLib].type != InstantDictType_LOCAL) -+ continue; -+ iRealLib = dictmask[iLib].index; -+ if (sWord) { -+ oLib[iRealLib]->LookupSynonym(sWord, iCurrent[iLib].synidx, iCurrent[iLib].synidx_suggest, EnableCollationLevel, servercollatefunc); -+ } -+ if (iCurrent[iLib].synidx==UNSET_INDEX) -+ continue; -+ if (iCurrent[iLib].synidx!=INVALID_INDEX) { -+ if ( iCurrent[iLib].synidx>=nsynarticles(iRealLib) || iCurrent[iLib].synidx<=0) -+ continue; -+ } -+ if ( poCurrentWord == NULL ) { -+ if (GetWordPrev(iCurrent[iLib].synidx, pidx, iRealLib, false, servercollatefunc)) { -+ poCurrentWord = poGetSynonymWord(pidx, iRealLib, servercollatefunc); -+ iCurrentLib = iLib; -+ iCurrentRealLib = iRealLib; -+ isLib=false; -+ } -+ } else { -+ if (GetWordPrev(iCurrent[iLib].synidx, pidx, iRealLib, false, servercollatefunc)) { -+ gint x; -+ word = poGetSynonymWord(pidx,iRealLib, servercollatefunc); -+ x = stardict_server_collate(poCurrentWord, word, EnableCollationLevel, CollateFunction, servercollatefunc); -+ if (x < 0 ) { -+ poCurrentWord = word; -+ iCurrentLib = iLib; -+ iCurrentRealLib = iRealLib; -+ isLib=false; -+ } -+ } -+ } -+ } -+ if (poCurrentWord) { -+ for (iLib=0;iLib<dictmask.size();iLib++) { -+ if (dictmask[iLib].type != InstantDictType_LOCAL) -+ continue; -+ iRealLib = dictmask[iLib].index; -+ if (isLib && (iLib == iCurrentLib)) -+ continue; -+ if (iCurrent[iLib].idx!=INVALID_INDEX) { -+ if (iCurrent[iLib].idx>=narticles(iRealLib) || iCurrent[iLib].idx<=0) -+ continue; -+ } -+ if (GetWordPrev(iCurrent[iLib].idx, pidx, iRealLib, true, servercollatefunc)) { -+ word = poGetWord(pidx, iRealLib, servercollatefunc); -+ if (strcmp(poCurrentWord, word) == 0) { -+ iCurrent[iLib].idx=pidx; -+ } -+ } -+ } -+ for (iLib=0;iLib<dictmask.size();iLib++) { -+ if (dictmask[iLib].type != InstantDictType_LOCAL) -+ continue; -+ iRealLib = dictmask[iLib].index; -+ if ((!isLib) && (iLib == iCurrentLib)) -+ continue; -+ if (iCurrent[iLib].synidx==UNSET_INDEX) -+ continue; -+ if (iCurrent[iLib].synidx!=INVALID_INDEX) { -+ if (iCurrent[iLib].synidx>=nsynarticles(iRealLib) || iCurrent[iLib].synidx<=0) -+ continue; -+ } -+ if (GetWordPrev(iCurrent[iLib].synidx, pidx, iRealLib, false, servercollatefunc)) { -+ word = poGetSynonymWord(pidx, iRealLib, servercollatefunc); -+ if (strcmp(poCurrentWord, word) == 0) { -+ iCurrent[iLib].synidx=pidx; -+ } -+ } -+ } -+ if (isLib) { -+ GetWordPrev(iCurrent[iCurrentLib].idx, pidx, iCurrentRealLib, true, servercollatefunc); -+ iCurrent[iCurrentLib].idx = pidx; -+ } else { -+ GetWordPrev(iCurrent[iCurrentLib].synidx, pidx, iCurrentRealLib, false, servercollatefunc); -+ iCurrent[iCurrentLib].synidx = pidx; -+ } -+ } -+ return poCurrentWord; -+} -+ -+bool Libs::LookupSynonymSimilarWord(const gchar* sWord, glong &iSynonymWordIndex, glong &synidx_suggest, size_t iLib, int servercollatefunc) -+{ -+ if (oLib[iLib]->syn_file.get() == NULL) -+ return false; -+ -+ glong iIndex; -+ glong iIndex_suggest; -+ bool bFound=false; -+ gchar *casestr; -+ bool bLookup; -+ -+ if (!bFound) { -+ // to lower case. -+ casestr = g_utf8_strdown(sWord, -1); -+ if (strcmp(casestr, sWord)) { -+ bLookup = oLib[iLib]->LookupSynonym(casestr, iIndex, iIndex_suggest, EnableCollationLevel, servercollatefunc); -+ if(bLookup) -+ bFound=true; -+ } -+ g_free(casestr); -+ // to upper case. -+ if (!bFound) { -+ casestr = g_utf8_strup(sWord, -1); -+ if (strcmp(casestr, sWord)) { -+ bLookup = oLib[iLib]->LookupSynonym(casestr, iIndex, iIndex_suggest, EnableCollationLevel, servercollatefunc); -+ if(bLookup) -+ bFound=true; -+ } -+ g_free(casestr); -+ } -+ // Upper the first character and lower others. -+ if (!bFound) { -+ gchar *nextchar = g_utf8_next_char(sWord); -+ gchar *firstchar = g_utf8_strup(sWord, nextchar - sWord); -+ nextchar = g_utf8_strdown(nextchar, -1); -+ casestr = g_strdup_printf("%s%s", firstchar, nextchar); -+ g_free(firstchar); -+ g_free(nextchar); -+ if (strcmp(casestr, sWord)) { -+ bLookup = oLib[iLib]->LookupSynonym(casestr, iIndex, iIndex_suggest, EnableCollationLevel, servercollatefunc); -+ if(bLookup) -+ bFound=true; -+ } -+ g_free(casestr); -+ } -+ if (!bFound) { -+ iIndex = iSynonymWordIndex; -+ glong pidx; -+ const gchar *cword; -+ do { -+ if (GetWordPrev(iIndex, pidx, iLib, false, servercollatefunc)) { -+ cword = poGetSynonymWord(pidx, iLib, servercollatefunc); -+ if (stardict_casecmp(cword, sWord, EnableCollationLevel, CollateFunction, servercollatefunc)==0) { -+ iIndex = pidx; -+ bFound=true; -+ } else { -+ break; -+ } -+ } else { -+ break; -+ } -+ } while (true); -+ if (!bFound) { -+ if (iIndex!=INVALID_INDEX) { -+ cword = poGetSynonymWord(iIndex, iLib, servercollatefunc); -+ if (stardict_casecmp(cword, sWord, EnableCollationLevel, CollateFunction, servercollatefunc)==0) { -+ bFound=true; -+ } -+ } -+ } -+ } -+ } -+ if (bFound) { -+ iSynonymWordIndex = iIndex; -+ synidx_suggest = iIndex_suggest; -+ } -+ return bFound; -+} -+ -+bool Libs::LookupSimilarWord(const gchar* sWord, glong & iWordIndex, glong &idx_suggest, size_t iLib, int servercollatefunc) -+{ -+ glong iIndex; -+ bool bFound=false; -+ gchar *casestr; -+ -+ if (!bFound) { -+ // to lower case. -+ casestr = g_utf8_strdown(sWord, -1); -+ if (strcmp(casestr, sWord)) { -+ if(oLib[iLib]->Lookup(casestr, iIndex, idx_suggest, EnableCollationLevel, servercollatefunc)) -+ bFound=true; -+ } -+ g_free(casestr); -+ // to upper case. -+ if (!bFound) { -+ casestr = g_utf8_strup(sWord, -1); -+ if (strcmp(casestr, sWord)) { -+ if(oLib[iLib]->Lookup(casestr, iIndex, idx_suggest, EnableCollationLevel, servercollatefunc)) -+ bFound=true; -+ } -+ g_free(casestr); -+ } -+ // Upper the first character and lower others. -+ if (!bFound) { -+ gchar *nextchar = g_utf8_next_char(sWord); -+ gchar *firstchar = g_utf8_strup(sWord, nextchar - sWord); -+ nextchar = g_utf8_strdown(nextchar, -1); -+ casestr = g_strdup_printf("%s%s", firstchar, nextchar); -+ g_free(firstchar); -+ g_free(nextchar); -+ if (strcmp(casestr, sWord)) { -+ if(oLib[iLib]->Lookup(casestr, iIndex, idx_suggest, EnableCollationLevel, servercollatefunc)) -+ bFound=true; -+ } -+ g_free(casestr); -+ } -+ if (!bFound) { -+ iIndex = iWordIndex; -+ glong pidx; -+ const gchar *cword; -+ do { -+ if (GetWordPrev(iIndex, pidx, iLib, true, servercollatefunc)) { -+ cword = poGetWord(pidx, iLib, servercollatefunc); -+ if (stardict_casecmp(cword, sWord, EnableCollationLevel, CollateFunction, servercollatefunc)==0) { -+ iIndex = pidx; -+ bFound=true; -+ } else { -+ break; -+ } -+ } else { -+ break; -+ } -+ } while (true); -+ if (!bFound) { -+ if (iIndex!=INVALID_INDEX) { -+ cword = poGetWord(iIndex, iLib, servercollatefunc); -+ if (stardict_casecmp(cword, sWord, EnableCollationLevel, CollateFunction, servercollatefunc)==0) { -+ bFound=true; -+ } -+ } -+ } -+ } -+ } -+ -+ if (bIsPureEnglish(sWord)) { -+ // If not Found , try other status of sWord. -+ size_t iWordLen=strlen(sWord); -+ bool isupcase; -+ -+ gchar *sNewWord = (gchar *)g_malloc(iWordLen + 1); -+ -+ //cut one char "s" or "d" -+ if(!bFound && iWordLen>1) { -+ isupcase = sWord[iWordLen-1]=='S' || !strncmp(&sWord[iWordLen-2],"ED",2); -+ if (isupcase || sWord[iWordLen-1]=='s' || !strncmp(&sWord[iWordLen-2],"ed",2)) { -+ strcpy(sNewWord,sWord); -+ sNewWord[iWordLen-1]='\0'; // cut "s" or "d" -+ if (oLib[iLib]->Lookup(sNewWord, iIndex, idx_suggest, EnableCollationLevel, servercollatefunc)) -+ bFound=true; -+ else if (isupcase || g_ascii_isupper(sWord[0])) { -+ casestr = g_ascii_strdown(sNewWord, -1); -+ if (strcmp(casestr, sNewWord)) { -+ if(oLib[iLib]->Lookup(casestr, iIndex, idx_suggest, EnableCollationLevel, servercollatefunc)) -+ bFound=true; -+ } -+ g_free(casestr); -+ } -+ } -+ } -+ -+ //cut "ly" -+ if(!bFound && iWordLen>2) { -+ isupcase = !strncmp(&sWord[iWordLen-2],"LY",2); -+ if (isupcase || (!strncmp(&sWord[iWordLen-2],"ly",2))) { -+ strcpy(sNewWord,sWord); -+ sNewWord[iWordLen-2]='\0'; // cut "ly" -+ if (iWordLen>5 && sNewWord[iWordLen-3]==sNewWord[iWordLen-4] -+ && !bIsVowel(sNewWord[iWordLen-4]) && -+ bIsVowel(sNewWord[iWordLen-5])) {//doubled -+ -+ sNewWord[iWordLen-3]='\0'; -+ if(oLib[iLib]->Lookup(sNewWord, iIndex, idx_suggest, EnableCollationLevel, servercollatefunc)) -+ bFound=true; -+ else { -+ if (isupcase || g_ascii_isupper(sWord[0])) { -+ casestr = g_ascii_strdown(sNewWord, -1); -+ if (strcmp(casestr, sNewWord)) { -+ if(oLib[iLib]->Lookup(casestr, iIndex, idx_suggest, EnableCollationLevel, servercollatefunc)) -+ bFound=true; -+ } -+ g_free(casestr); -+ } -+ if (!bFound) -+ sNewWord[iWordLen-3]=sNewWord[iWordLen-4]; //restore -+ } -+ } -+ if (!bFound) { -+ if (oLib[iLib]->Lookup(sNewWord, iIndex, idx_suggest, EnableCollationLevel, servercollatefunc)) -+ bFound=true; -+ else if (isupcase || g_ascii_isupper(sWord[0])) { -+ casestr = g_ascii_strdown(sNewWord, -1); -+ if (strcmp(casestr, sNewWord)) { -+ if(oLib[iLib]->Lookup(casestr, iIndex, idx_suggest, EnableCollationLevel, servercollatefunc)) -+ bFound=true; -+ } -+ g_free(casestr); -+ } -+ } -+ } -+ } -+ -+ //cut "ing" -+ if(!bFound && iWordLen>3) { -+ isupcase = !strncmp(&sWord[iWordLen-3],"ING",3); -+ if (isupcase || !strncmp(&sWord[iWordLen-3],"ing",3) ) { -+ strcpy(sNewWord,sWord); -+ sNewWord[iWordLen-3]='\0'; -+ if ( iWordLen>6 && (sNewWord[iWordLen-4]==sNewWord[iWordLen-5]) -+ && !bIsVowel(sNewWord[iWordLen-5]) && -+ bIsVowel(sNewWord[iWordLen-6])) { //doubled -+ sNewWord[iWordLen-4]='\0'; -+ if (oLib[iLib]->Lookup(sNewWord, iIndex, idx_suggest, EnableCollationLevel, servercollatefunc)) -+ bFound=true; -+ else { -+ if (isupcase || g_ascii_isupper(sWord[0])) { -+ casestr = g_ascii_strdown(sNewWord, -1); -+ if (strcmp(casestr, sNewWord)) { -+ if(oLib[iLib]->Lookup(casestr, iIndex, idx_suggest, EnableCollationLevel, servercollatefunc)) -+ bFound=true; -+ } -+ g_free(casestr); -+ } -+ if (!bFound) -+ sNewWord[iWordLen-4]=sNewWord[iWordLen-5]; //restore -+ } -+ } -+ if( !bFound ) { -+ if (oLib[iLib]->Lookup(sNewWord, iIndex, idx_suggest, EnableCollationLevel, servercollatefunc)) -+ bFound=true; -+ else if (isupcase || g_ascii_isupper(sWord[0])) { -+ casestr = g_ascii_strdown(sNewWord, -1); -+ if (strcmp(casestr, sNewWord)) { -+ if(oLib[iLib]->Lookup(casestr, iIndex, idx_suggest, EnableCollationLevel, servercollatefunc)) -+ bFound=true; -+ } -+ g_free(casestr); -+ } -+ } -+ if(!bFound) { -+ if (isupcase) -+ strcat(sNewWord,"E"); // add a char "E" -+ else -+ strcat(sNewWord,"e"); // add a char "e" -+ if(oLib[iLib]->Lookup(sNewWord, iIndex, idx_suggest, EnableCollationLevel, servercollatefunc)) -+ bFound=true; -+ else if (isupcase || g_ascii_isupper(sWord[0])) { -+ casestr = g_ascii_strdown(sNewWord, -1); -+ if (strcmp(casestr, sNewWord)) { -+ if(oLib[iLib]->Lookup(casestr, iIndex, idx_suggest, EnableCollationLevel, servercollatefunc)) -+ bFound=true; -+ } -+ g_free(casestr); -+ } -+ } -+ } -+ } -+ -+ //cut two char "es" -+ if(!bFound && iWordLen>3) { -+ isupcase = (!strncmp(&sWord[iWordLen-2],"ES",2) && -+ (sWord[iWordLen-3] == 'S' || -+ sWord[iWordLen-3] == 'X' || -+ sWord[iWordLen-3] == 'O' || -+ (iWordLen >4 && sWord[iWordLen-3] == 'H' && -+ (sWord[iWordLen-4] == 'C' || -+ sWord[iWordLen-4] == 'S')))); -+ if (isupcase || -+ (!strncmp(&sWord[iWordLen-2],"es",2) && -+ (sWord[iWordLen-3] == 's' || sWord[iWordLen-3] == 'x' || -+ sWord[iWordLen-3] == 'o' || -+ (iWordLen >4 && sWord[iWordLen-3] == 'h' && -+ (sWord[iWordLen-4] == 'c' || sWord[iWordLen-4] == 's'))))) { -+ strcpy(sNewWord,sWord); -+ sNewWord[iWordLen-2]='\0'; -+ if(oLib[iLib]->Lookup(sNewWord, iIndex, idx_suggest, EnableCollationLevel, servercollatefunc)) -+ bFound=true; -+ else if (isupcase || g_ascii_isupper(sWord[0])) { -+ casestr = g_ascii_strdown(sNewWord, -1); -+ if (strcmp(casestr, sNewWord)) { -+ if(oLib[iLib]->Lookup(casestr, iIndex, idx_suggest, EnableCollationLevel, servercollatefunc)) -+ bFound=true; -+ } -+ g_free(casestr); -+ } -+ } -+ } -+ -+ //cut "ed" -+ if (!bFound && iWordLen>3) { -+ isupcase = !strncmp(&sWord[iWordLen-2],"ED",2); -+ if (isupcase || !strncmp(&sWord[iWordLen-2],"ed",2)) { -+ strcpy(sNewWord,sWord); -+ sNewWord[iWordLen-2]='\0'; -+ if (iWordLen>5 && (sNewWord[iWordLen-3]==sNewWord[iWordLen-4]) -+ && !bIsVowel(sNewWord[iWordLen-4]) && -+ bIsVowel(sNewWord[iWordLen-5])) {//doubled -+ sNewWord[iWordLen-3]='\0'; -+ if (oLib[iLib]->Lookup(sNewWord, iIndex, idx_suggest, EnableCollationLevel, servercollatefunc)) -+ bFound=true; -+ else { -+ if (isupcase || g_ascii_isupper(sWord[0])) { -+ casestr = g_ascii_strdown(sNewWord, -1); -+ if (strcmp(casestr, sNewWord)) { -+ if(oLib[iLib]->Lookup(casestr, iIndex, idx_suggest, EnableCollationLevel, servercollatefunc)) -+ bFound=true; -+ } -+ g_free(casestr); -+ } -+ if (!bFound) -+ sNewWord[iWordLen-3]=sNewWord[iWordLen-4]; //restore -+ } -+ } -+ if (!bFound) { -+ if (oLib[iLib]->Lookup(sNewWord, iIndex, idx_suggest, EnableCollationLevel, servercollatefunc)) -+ bFound=true; -+ else if (isupcase || g_ascii_isupper(sWord[0])) { -+ casestr = g_ascii_strdown(sNewWord, -1); -+ if (strcmp(casestr, sNewWord)) { -+ if(oLib[iLib]->Lookup(casestr, iIndex, idx_suggest, EnableCollationLevel, servercollatefunc)) -+ bFound=true; -+ } -+ g_free(casestr); -+ } -+ } -+ } -+ } -+ -+ // cut "ied" , add "y". -+ if (!bFound && iWordLen>3) { -+ isupcase = !strncmp(&sWord[iWordLen-3],"IED",3); -+ if (isupcase || (!strncmp(&sWord[iWordLen-3],"ied",3))) { -+ strcpy(sNewWord,sWord); -+ sNewWord[iWordLen-3]='\0'; -+ if (isupcase) -+ strcat(sNewWord,"Y"); // add a char "Y" -+ else -+ strcat(sNewWord,"y"); // add a char "y" -+ if (oLib[iLib]->Lookup(sNewWord, iIndex, idx_suggest, EnableCollationLevel, servercollatefunc)) -+ bFound=true; -+ else if (isupcase || g_ascii_isupper(sWord[0])) { -+ casestr = g_ascii_strdown(sNewWord, -1); -+ if (strcmp(casestr, sNewWord)) { -+ if(oLib[iLib]->Lookup(casestr, iIndex, idx_suggest, EnableCollationLevel, servercollatefunc)) -+ bFound=true; -+ } -+ g_free(casestr); -+ } -+ } -+ } -+ -+ // cut "ies" , add "y". -+ if (!bFound && iWordLen>3) { -+ isupcase = !strncmp(&sWord[iWordLen-3],"IES",3); -+ if (isupcase || (!strncmp(&sWord[iWordLen-3],"ies",3))) { -+ strcpy(sNewWord,sWord); -+ sNewWord[iWordLen-3]='\0'; -+ if (isupcase) -+ strcat(sNewWord,"Y"); // add a char "Y" -+ else -+ strcat(sNewWord,"y"); // add a char "y" -+ if(oLib[iLib]->Lookup(sNewWord, iIndex, idx_suggest, EnableCollationLevel, servercollatefunc)) -+ bFound=true; -+ else if (isupcase || g_ascii_isupper(sWord[0])) { -+ casestr = g_ascii_strdown(sNewWord, -1); -+ if (strcmp(casestr, sNewWord)) { -+ if(oLib[iLib]->Lookup(casestr, iIndex, idx_suggest, EnableCollationLevel, servercollatefunc)) -+ bFound=true; -+ } -+ g_free(casestr); -+ } -+ } -+ } -+ -+ // cut "er". -+ if (!bFound && iWordLen>2) { -+ isupcase = !strncmp(&sWord[iWordLen-2],"ER",2); -+ if (isupcase || (!strncmp(&sWord[iWordLen-2],"er",2))) { -+ strcpy(sNewWord,sWord); -+ sNewWord[iWordLen-2]='\0'; -+ if(oLib[iLib]->Lookup(sNewWord, iIndex, idx_suggest, EnableCollationLevel, servercollatefunc)) -+ bFound=true; -+ else if (isupcase || g_ascii_isupper(sWord[0])) { -+ casestr = g_ascii_strdown(sNewWord, -1); -+ if (strcmp(casestr, sNewWord)) { -+ if(oLib[iLib]->Lookup(casestr, iIndex, idx_suggest, EnableCollationLevel, servercollatefunc)) -+ bFound=true; -+ } -+ g_free(casestr); -+ } -+ } -+ } -+ -+ // cut "est". -+ if (!bFound && iWordLen>3) { -+ isupcase = !strncmp(&sWord[iWordLen-3], "EST", 3); -+ if (isupcase || (!strncmp(&sWord[iWordLen-3],"est", 3))) { -+ strcpy(sNewWord,sWord); -+ sNewWord[iWordLen-3]='\0'; -+ if(oLib[iLib]->Lookup(sNewWord, iIndex, idx_suggest, EnableCollationLevel, servercollatefunc)) -+ bFound=true; -+ else if (isupcase || g_ascii_isupper(sWord[0])) { -+ casestr = g_ascii_strdown(sNewWord, -1); -+ if (strcmp(casestr, sNewWord)) { -+ if(oLib[iLib]->Lookup(casestr, iIndex, idx_suggest, EnableCollationLevel, servercollatefunc)) -+ bFound=true; -+ } -+ g_free(casestr); -+ } -+ } -+ } -+ -+ g_free(sNewWord); -+ } -+ -+ if (bFound) -+ iWordIndex = iIndex; -+#if 0 -+ else { -+ //don't change iWordIndex here. -+ //when LookupSimilarWord all failed too, we want to use the old LookupWord index to list words. -+ //iWordIndex = INVALID_INDEX; -+ } -+#endif -+ return bFound; -+} -+ -+bool Libs::SimpleLookupWord(const gchar* sWord, glong & iWordIndex, glong &idx_suggest, size_t iLib, int servercollatefunc) -+{ -+ bool bFound = oLib[iLib]->Lookup(sWord, iWordIndex, idx_suggest, EnableCollationLevel, servercollatefunc); -+ if (!bFound) -+ bFound = LookupSimilarWord(sWord, iWordIndex, idx_suggest, iLib, servercollatefunc); -+ return bFound; -+} -+ -+bool Libs::SimpleLookupSynonymWord(const gchar* sWord, glong & iWordIndex, glong &synidx_suggest, size_t iLib, int servercollatefunc) -+{ -+ bool bFound = oLib[iLib]->LookupSynonym(sWord, iWordIndex, synidx_suggest, EnableCollationLevel, servercollatefunc); -+ if (!bFound) -+ bFound = LookupSynonymSimilarWord(sWord, iWordIndex, synidx_suggest, iLib, servercollatefunc); -+ return bFound; -+} -+ -+struct Fuzzystruct { -+ char * pMatchWord; -+ int iMatchWordDistance; -+}; -+ -+static inline bool operator<(const Fuzzystruct & lh, const Fuzzystruct & rh) { -+ if (lh.iMatchWordDistance!=rh.iMatchWordDistance) -+ return lh.iMatchWordDistance<rh.iMatchWordDistance; -+ -+ if (lh.pMatchWord && rh.pMatchWord) -+ return stardict_strcmp(lh.pMatchWord, rh.pMatchWord)<0; -+ -+ return false; -+} -+ -+static inline void unicode_strdown(gunichar *str) -+{ -+ while (*str) { -+ *str=g_unichar_tolower(*str); -+ ++str; -+ } -+} -+ -+bool Libs::LookupWithFuzzy(const gchar *sWord, gchar *reslist[], gint reslist_size, std::vector<InstantDictIndex> &dictmask) -+{ -+ if (sWord[0] == '\0') -+ return false; -+ -+ std::vector<Fuzzystruct> oFuzzystruct(reslist_size); -+ -+ for (int i=0; i<reslist_size; i++) { -+ oFuzzystruct[i].pMatchWord = NULL; -+ oFuzzystruct[i].iMatchWordDistance = iMaxFuzzyDistance; -+ } -+ int iMaxDistance = iMaxFuzzyDistance; -+ int iDistance; -+ bool Found = false; -+ EditDistance oEditDistance; -+ -+ glong iCheckWordLen; -+ const char *sCheck; -+ gunichar *ucs4_str1, *ucs4_str2; -+ glong ucs4_str2_len; -+ -+ ucs4_str2 = g_utf8_to_ucs4_fast(sWord, -1, &ucs4_str2_len); -+ unicode_strdown(ucs4_str2); -+ -+ std::vector<Dict *>::size_type iRealLib; -+ for (std::vector<InstantDictIndex>::size_type iLib=0; iLib<dictmask.size(); iLib++) { -+ if (dictmask[iLib].type != InstantDictType_LOCAL) -+ continue; -+ iRealLib = dictmask[iLib].index; -+ for (gint synLib=0; synLib<2; synLib++) { -+ if (synLib==1) { -+ if (oLib[iRealLib]->syn_file.get()==NULL) -+ break; -+ } -+ show_progress->notify_about_work(); -+ -+ //if (stardict_strcmp(sWord, poGetWord(0,iRealLib))>=0 && stardict_strcmp(sWord, poGetWord(narticles(iRealLib)-1,iRealLib))<=0) { -+ //there are Chinese dicts and English dicts... -+ if (TRUE) { -+ glong iwords; -+ if (synLib==0) -+ iwords = narticles(iRealLib); -+ else -+ iwords = nsynarticles(iRealLib); -+ for (glong index=0; index<iwords; index++) { -+ // Need to deal with same word in index? But this will slow down processing in most case. -+ if (synLib==0) -+ sCheck = poGetOrigWord(index,iRealLib); -+ else -+ sCheck = poGetOrigSynonymWord(index,iRealLib); -+ // tolower and skip too long or too short words -+ iCheckWordLen = g_utf8_strlen(sCheck, -1); -+ if (iCheckWordLen-ucs4_str2_len>=iMaxDistance || -+ ucs4_str2_len-iCheckWordLen>=iMaxDistance) -+ continue; -+ ucs4_str1 = g_utf8_to_ucs4_fast(sCheck, -1, NULL); -+ if (iCheckWordLen > ucs4_str2_len) -+ ucs4_str1[ucs4_str2_len]=0; -+ unicode_strdown(ucs4_str1); -+ -+ iDistance = oEditDistance.CalEditDistance(ucs4_str1, ucs4_str2, iMaxDistance); -+ g_free(ucs4_str1); -+ if (iDistance<iMaxDistance && iDistance < ucs4_str2_len) { -+ // when ucs4_str2_len=1,2 we need less fuzzy. -+ Found = true; -+ bool bAlreadyInList = false; -+ int iMaxDistanceAt=0; -+ for (int j=0; j<reslist_size; j++) { -+ if (oFuzzystruct[j].pMatchWord && -+ strcmp(oFuzzystruct[j].pMatchWord,sCheck)==0 ) {//already in list -+ bAlreadyInList = true; -+ break; -+ } -+ //find the position,it will certainly be found (include the first time) as iMaxDistance is set by last time. -+ if (oFuzzystruct[j].iMatchWordDistance == iMaxDistance ) { -+ iMaxDistanceAt = j; -+ } -+ } -+ if (!bAlreadyInList) { -+ if (oFuzzystruct[iMaxDistanceAt].pMatchWord) -+ g_free(oFuzzystruct[iMaxDistanceAt].pMatchWord); -+ oFuzzystruct[iMaxDistanceAt].pMatchWord = g_strdup(sCheck); -+ oFuzzystruct[iMaxDistanceAt].iMatchWordDistance = iDistance; -+ // calc new iMaxDistance -+ iMaxDistance = iDistance; -+ for (int j=0; j<reslist_size; j++) { -+ if (oFuzzystruct[j].iMatchWordDistance > iMaxDistance) -+ iMaxDistance = oFuzzystruct[j].iMatchWordDistance; -+ } // calc new iMaxDistance -+ } // add to list -+ } // find one -+ } // each word -+ } // ok for search -+ } // synLib -+ } // each lib -+ g_free(ucs4_str2); -+ -+ if (Found)// sort with distance -+ std::sort(oFuzzystruct.begin(), oFuzzystruct.end()); -+ -+ for (gint i=0; i<reslist_size; ++i) -+ reslist[i]=oFuzzystruct[i].pMatchWord; -+ -+ return Found; -+} -+ -+static inline bool less_for_compare(const char *lh, const char *rh) { -+ return stardict_strcmp(lh, rh)<0; -+} -+ -+gint Libs::LookupWithRule(const gchar *word, gchar **ppMatchWord, std::vector<InstantDictIndex> &dictmask) -+{ -+ glong aiIndex[MAX_MATCH_ITEM_PER_LIB+1]; -+ gint iMatchCount = 0; -+ GPatternSpec *pspec = g_pattern_spec_new(word); -+ -+ const gchar * sMatchWord; -+ bool bAlreadyInList; -+ std::vector<Dict *>::size_type iRealLib; -+ for (std::vector<InstantDictIndex>::size_type iLib=0; iLib<dictmask.size(); iLib++) { -+ //if(oLibs.LookdupWordsWithRule(pspec,aiIndex,MAX_MATCH_ITEM_PER_LIB+1-iMatchCount,iLib)) -+ // -iMatchCount,so save time,but may got less result and the word may repeat. -+ if (dictmask[iLib].type != InstantDictType_LOCAL) -+ continue; -+ iRealLib = dictmask[iLib].index; -+ if (oLib[iRealLib]->LookupWithRule(pspec, aiIndex, MAX_MATCH_ITEM_PER_LIB+1)) { -+ show_progress->notify_about_work(); -+ for (int i=0; aiIndex[i]!=-1; i++) { -+ sMatchWord = poGetOrigWord(aiIndex[i],iRealLib); -+ bAlreadyInList = false; -+ for (int j=0; j<iMatchCount; j++) { -+ if (strcmp(ppMatchWord[j],sMatchWord)==0) {//already in list -+ bAlreadyInList = true; -+ break; -+ } -+ } -+ if (!bAlreadyInList) -+ ppMatchWord[iMatchCount++] = g_strdup(sMatchWord); -+ } -+ } -+ if (oLib[iRealLib]->LookupWithRuleSynonym(pspec, aiIndex, MAX_MATCH_ITEM_PER_LIB+1)) { -+ show_progress->notify_about_work(); -+ for (int i=0; aiIndex[i]!=-1; i++) { -+ sMatchWord = poGetOrigSynonymWord(aiIndex[i],iRealLib); -+ bAlreadyInList = false; -+ for (int j=0; j<iMatchCount; j++) { -+ if (strcmp(ppMatchWord[j],sMatchWord)==0) {//already in list -+ bAlreadyInList = true; -+ break; -+ } -+ } -+ if (!bAlreadyInList) -+ ppMatchWord[iMatchCount++] = g_strdup(sMatchWord); -+ } -+ } -+ } -+ g_pattern_spec_free(pspec); -+ -+ if (iMatchCount)// sort it. -+ std::sort(ppMatchWord, ppMatchWord+iMatchCount, less_for_compare); -+ return iMatchCount; -+} -+ -+gint Libs::LookupWithRegex(const gchar *word, gchar **ppMatchWord, std::vector<InstantDictIndex> &dictmask) -+{ -+ glong aiIndex[MAX_MATCH_ITEM_PER_LIB+1]; -+ gint iMatchCount = 0; -+ GRegex *regex = g_regex_new(word, G_REGEX_OPTIMIZE, (GRegexMatchFlags)0, NULL); -+ -+ const gchar * sMatchWord; -+ bool bAlreadyInList; -+ std::vector<Dict *>::size_type iRealLib; -+ for (std::vector<InstantDictIndex>::size_type iLib=0; iLib<dictmask.size(); iLib++) { -+ //if(oLibs.LookdupWordsWithRule(pspec,aiIndex,MAX_MATCH_ITEM_PER_LIB+1-iMatchCount,iLib)) -+ // -iMatchCount,so save time,but may got less result and the word may repeat. -+ if (dictmask[iLib].type != InstantDictType_LOCAL) -+ continue; -+ iRealLib = dictmask[iLib].index; -+ if (oLib[iRealLib]->LookupWithRegex(regex, aiIndex, MAX_MATCH_ITEM_PER_LIB+1)) { -+ show_progress->notify_about_work(); -+ for (int i=0; aiIndex[i]!=-1; i++) { -+ sMatchWord = poGetOrigWord(aiIndex[i],iRealLib); -+ bAlreadyInList = false; -+ for (int j=0; j<iMatchCount; j++) { -+ if (strcmp(ppMatchWord[j],sMatchWord)==0) {//already in list -+ bAlreadyInList = true; -+ break; -+ } -+ } -+ if (!bAlreadyInList) -+ ppMatchWord[iMatchCount++] = g_strdup(sMatchWord); -+ } -+ } -+ if (oLib[iRealLib]->LookupWithRegexSynonym(regex, aiIndex, MAX_MATCH_ITEM_PER_LIB+1)) { -+ show_progress->notify_about_work(); -+ for (int i=0; aiIndex[i]!=-1; i++) { -+ sMatchWord = poGetOrigSynonymWord(aiIndex[i],iRealLib); -+ bAlreadyInList = false; -+ for (int j=0; j<iMatchCount; j++) { -+ if (strcmp(ppMatchWord[j],sMatchWord)==0) {//already in list -+ bAlreadyInList = true; -+ break; -+ } -+ } -+ if (!bAlreadyInList) -+ ppMatchWord[iMatchCount++] = g_strdup(sMatchWord); -+ } -+ } -+ } -+ g_regex_unref(regex); -+ -+ if (iMatchCount)// sort it. -+ std::sort(ppMatchWord, ppMatchWord+iMatchCount, less_for_compare); -+ return iMatchCount; -+} -+ -+bool Libs::LookupData(const gchar *sWord, std::vector<gchar *> *reslist, updateSearchDialog_func search_func, gpointer search_data, bool *cancel, std::vector<InstantDictIndex> &dictmask) -+{ -+ std::vector<std::string> SearchWords; -+ std::string SearchWord; -+ const char *p=sWord; -+ while (*p) { -+ if (*p=='\\') { -+ p++; -+ switch (*p) { -+ case ' ': -+ SearchWord+=' '; -+ break; -+ case '\\': -+ SearchWord+='\\'; -+ break; -+ case 't': -+ SearchWord+='\t'; -+ break; -+ case 'n': -+ SearchWord+='\n'; -+ break; -+ default: -+ SearchWord+=*p; -+ } -+ } else if (*p == ' ') { -+ if (!SearchWord.empty()) { -+ SearchWords.push_back(SearchWord); -+ SearchWord.clear(); -+ } -+ } else { -+ SearchWord+=*p; -+ } -+ p++; -+ } -+ if (!SearchWord.empty()) { -+ SearchWords.push_back(SearchWord); -+ SearchWord.clear(); -+ } -+ if (SearchWords.empty()) -+ return false; -+ -+ glong search_count=0; -+ glong total_count=0; -+ if (search_func) { -+ for (std::vector<InstantDictIndex>::size_type i=0; i<dictmask.size(); ++i) { -+ if (dictmask[i].type == InstantDictType_LOCAL) -+ total_count += narticles(dictmask[i].index); -+ } -+ } -+ -+ guint32 max_size =0; -+ gchar *origin_data = NULL; -+ std::vector<InstantDictIndex>::size_type iRealLib; -+ for (std::vector<InstantDictIndex>::size_type i=0; i<dictmask.size(); ++i) { -+ if (dictmask[i].type != InstantDictType_LOCAL) -+ continue; -+ iRealLib = dictmask[i].index; -+ if (!oLib[iRealLib]->containSearchData()) -+ continue; -+ const gulong iwords = narticles(iRealLib); -+ const gchar *key; -+ guint32 offset, size; -+ for (gulong j=0; j<iwords; ++j) { -+ if (search_func) { -+ if (*cancel) -+ goto search_out; -+ if (search_count % 10000 == 0) { -+ search_func(search_data, (gdouble)search_count/(gdouble)total_count); -+ } -+ search_count++; -+ } -+ oLib[iRealLib]->get_key_and_data(j, &key, &offset, &size); -+ if (size>max_size) { -+ origin_data = (gchar *)g_realloc(origin_data, size); -+ max_size = size; -+ } -+ if (oLib[iRealLib]->SearchData(SearchWords, offset, size, origin_data)) { -+ if (reslist[i].empty() || strcmp(reslist[i].back(), key)) -+ reslist[i].push_back(g_strdup(key)); -+ } -+ } -+ } -+search_out: -+ g_free(origin_data); -+ KMP_end(); -+ -+ std::vector<InstantDictIndex>::size_type i; -+ for (i=0; i<dictmask.size(); ++i) -+ if (!reslist[i].empty()) -+ break; -+ -+ return i!=dictmask.size(); -+} -+ -+int Libs::GetStorageType(size_t iLib) -+{ -+ if (oLib[iLib]->storage == NULL) -+ return -1; -+ return oLib[iLib]->storage->is_file_or_db; -+} -+ -+const char *Libs::GetStorageFilePath(size_t iLib, const char *key) -+{ -+ if (oLib[iLib]->storage == NULL) -+ return NULL; -+ return oLib[iLib]->storage->get_file_path(key); -+} -+ -+const char *Libs::GetStorageFileContent(size_t iLib, const char *key) -+{ -+ if (oLib[iLib]->storage == NULL) -+ return NULL; -+ return oLib[iLib]->storage->get_file_content(key); -+} -diff -Nur stardict-3.0.1.orig//src/lib/treedict.cpp stardict-3.0.1/src/lib/treedict.cpp ---- stardict-3.0.1.orig//src/lib/treedict.cpp 2007-09-20 20:09:52.000000000 -0500 -+++ stardict-3.0.1/src/lib/treedict.cpp 2010-05-24 00:53:36.378667536 -0500 -@@ -29,6 +29,7 @@ - #include "getuint32.h" - - #include "treedict.hpp" -+#include <cstring> - - GtkTreeStore *TreeDict::model=NULL; - -diff -Nur stardict-3.0.1.orig//src/lib/treedict.cpp~ stardict-3.0.1/src/lib/treedict.cpp~ ---- stardict-3.0.1.orig//src/lib/treedict.cpp~ 1969-12-31 18:00:00.000000000 -0600 -+++ stardict-3.0.1/src/lib/treedict.cpp~ 2007-09-20 20:09:52.000000000 -0500 -@@ -0,0 +1,197 @@ -+/* -+ * This file part of StarDict - A international dictionary for GNOME. -+ * http://stardict.sourceforge.net -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 3 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU Library General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -+ */ -+ -+/* -+ * Implementation of class to work with GtkTree -+ * based StarDict's dictionaries -+ */ -+#ifdef HAVE_CONFIG_H -+# include "config.h" -+#endif -+ -+#include "file.hpp" -+#include "getuint32.h" -+ -+#include "treedict.hpp" -+ -+GtkTreeStore *TreeDict::model=NULL; -+ -+TreeDict::TreeDict() -+{ -+ if (model) -+ return; -+ -+ // It is said G_TYPE_UINT will always be 32 bit. -+ // see http://bugzilla.gnome.org/show_bug.cgi?id=337966 -+ model = gtk_tree_store_new (3, G_TYPE_STRING, G_TYPE_UINT, G_TYPE_UINT); //word, offset, size -+} -+ -+bool TreeDict::load(const std::string& ifofilename) -+{ -+ gulong tdxfilesize; -+ if (!load_ifofile(ifofilename, &tdxfilesize)) -+ return false; -+ -+ std::string fullfilename(ifofilename); -+ fullfilename.replace(fullfilename.length()-sizeof("ifo")+1, sizeof("ifo")-1, "dict.dz"); -+ -+ if (g_file_test(fullfilename.c_str(), G_FILE_TEST_EXISTS)) { -+ dictdzfile.reset(new dictData); -+ if (!dictdzfile->open(fullfilename, 0)) { -+ //g_print("open file %s failed!\n",fullfilename); -+ return false; -+ } -+ } else { -+ fullfilename.erase(fullfilename.length()-sizeof(".dz")+1, sizeof(".dz")-1); -+ dictfile = fopen(fullfilename.c_str(),"rb"); -+ if (!dictfile) { -+ //g_print("open file %s failed!\n",fullfilename); -+ return false; -+ } -+ } -+ -+ fullfilename=ifofilename; -+ fullfilename.replace(fullfilename.length()-sizeof("ifo")+1, sizeof("ifo")-1, "tdx.gz"); -+ -+ gchar *buffer= NULL; -+ if (g_file_test(fullfilename.c_str(), G_FILE_TEST_EXISTS)) { -+ gzFile in; -+ in = gzopen(fullfilename.c_str(),"rb"); -+ if (in == NULL) { -+ //g_print("Open file %s failed!\n",idxfilename); -+ return false; -+ } -+ -+ buffer = (gchar *)g_malloc(tdxfilesize); -+ -+ gulong len; -+ len = gzread(in, buffer, tdxfilesize); -+ if (len < 0) { -+ g_free(buffer); -+ return false; -+ } -+ gzclose(in); -+ if (len != tdxfilesize) { -+ g_free(buffer); -+ return false; -+ } -+ } else { -+ fullfilename.erase(fullfilename.length()-sizeof(".gz")+1, sizeof(".gz")-1); -+ FILE *file; -+ if (!(file = fopen (fullfilename.c_str(), "rb"))) { -+ //g_print("Open file %s failed!\n",fullfilename); -+ return false; -+ } -+ buffer = (gchar *)g_malloc(tdxfilesize); -+ gulong read_len; -+ read_len = fread(buffer, 1, tdxfilesize, file); -+ fclose(file); -+ if (read_len!=tdxfilesize) { -+ g_free(buffer); -+ return false; -+ } -+ } -+ -+ gchar *tmp_buffer = buffer; -+ load_model(&tmp_buffer, NULL, 1); // tmp_buffer will be changed. -+ g_free(buffer); -+ return true; -+} -+ -+bool TreeDict::load_ifofile(const std::string& ifofilename, gulong *tdxfilesize) -+{ -+ DictInfo dict_info; -+ if (!dict_info.load_from_ifo_file(ifofilename, true)) -+ return false; -+ -+ *tdxfilesize = dict_info.index_file_size; -+ sametypesequence=dict_info.sametypesequence; -+ -+ return true; -+} -+ -+void TreeDict::load_model(gchar **buffer, GtkTreeIter *parent, guint32 count) -+{ -+ GtkTreeIter iter; -+ gchar *p1; -+ guint32 offset, size, subentry_count; -+ -+ for (guint32 i=0; i< count; i++) { -+ p1 = *buffer + strlen(*buffer) +1; -+ offset = g_ntohl(get_uint32(p1)); -+ p1 += sizeof(guint32); -+ size = g_ntohl(get_uint32(p1)); -+ p1 += sizeof(guint32); -+ subentry_count = g_ntohl(get_uint32(p1)); -+ p1 += sizeof(guint32); -+ gtk_tree_store_append(model, &iter, parent); -+ gtk_tree_store_set(model, &iter, 0, *buffer, 1, offset, 2, size, -1); -+ *buffer = p1; -+ if (subentry_count) -+ load_model(buffer, &iter, subentry_count); -+ } -+} -+ -+ -+/**************************************************/ -+TreeDicts::TreeDicts() -+{ -+} -+ -+TreeDicts::~TreeDicts() -+{ -+ for (std::vector<TreeDict *>::iterator it=oTreeDict.begin(); -+ it!=oTreeDict.end(); ++it) -+ delete *it; -+} -+ -+void TreeDicts::load_dict(const std::string& url) -+{ -+ TreeDict *lib = new TreeDict; -+ if (lib->load(url)) -+ oTreeDict.push_back(lib); -+ else -+ delete lib; -+} -+ -+class TreeDictLoader { -+public: -+ TreeDictLoader(TreeDicts& td_) : td(td_) {} -+ void operator()(const std::string& url, bool disable) { -+ if (!disable) -+ td.load_dict(url); -+ } -+private: -+ TreeDicts& td; -+}; -+ -+GtkTreeStore* TreeDicts::Load(const strlist_t& tree_dicts_dirs, -+ const strlist_t& order_list, -+ const strlist_t& disable_list) -+{ -+ TreeDictLoader load(*this); -+ for_each_file(tree_dicts_dirs, ".ifo", order_list, disable_list, load); -+ -+ return TreeDict::get_model(); -+} -+ -+gchar* TreeDicts::poGetWordData(guint32 offset, guint32 size, int iTreeDict) -+{ -+ return oTreeDict[iTreeDict]->GetWordData(offset, size); -+} -diff -Nur stardict-3.0.1.orig//src/pangoview.cpp stardict-3.0.1/src/pangoview.cpp ---- stardict-3.0.1.orig//src/pangoview.cpp 2007-09-25 02:11:48.000000000 -0500 -+++ stardict-3.0.1/src/pangoview.cpp 2010-05-24 00:53:36.378667536 -0500 -@@ -22,6 +22,8 @@ - # include "config.h" - #endif - -+#include <cstring> -+ - #include "gtktextviewpango.h" - #include "utils.h" - #include "skin.h"//for SkinCursor definition -diff -Nur stardict-3.0.1.orig//src/pangoview.cpp~ stardict-3.0.1/src/pangoview.cpp~ ---- stardict-3.0.1.orig//src/pangoview.cpp~ 1969-12-31 18:00:00.000000000 -0600 -+++ stardict-3.0.1/src/pangoview.cpp~ 2007-09-25 02:11:48.000000000 -0500 -@@ -0,0 +1,499 @@ -+/* -+ * This file part of StarDict - A international dictionary for GNOME. -+ * http://stardict.sourceforge.net -+ * Copyright (C) 2005-2006 Evgeniy <dushistov@mail.ru> -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 3 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU Library General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -+ */ -+ -+#ifdef HAVE_CONFIG_H -+# include "config.h" -+#endif -+ -+#include "gtktextviewpango.h" -+#include "utils.h" -+#include "skin.h"//for SkinCursor definition -+ -+#include "pangoview.h" -+ -+class TextPangoWidget : public PangoWidgetBase { -+public: -+ TextPangoWidget(); -+ GtkWidget *widget() { return GTK_WIDGET(textview_); } -+ -+ void clear(); -+ void append_mark(const char *mark); -+ void append_pixbuf(GdkPixbuf *pixbuf, const char *label); -+ void append_widget(GtkWidget *widget); -+ void begin_update(); -+ void end_update(); -+ std::string get_text(); -+ void append_pango_text_with_links(const std::string&, -+ const LinksPosList&); -+protected: -+ void do_set_text(const char *str); -+ void do_append_text(const char *str); -+ void do_append_pango_text(const char *str); -+ void do_set_pango_text(const char *str); -+private: -+ GtkTextView *textview_; -+ std::list<GtkTextMark *> marklist_; -+ struct TextBufPos { -+ gint beg_; -+ gint end_; -+ std::string link_; -+ TextBufPos(gint beg, gint end, std::string link): beg_(beg), end_(end), link_(link) {} -+ }; -+ typedef std::vector<TextBufPos> TextBufLinks; -+ -+ TextBufLinks tb_links_; -+ GtkTextIter iter_; -+ SkinCursor hand_cursor_, regular_cursor_; -+ -+ static gboolean on_mouse_move(GtkWidget *, GdkEventMotion *, gpointer); -+ static gboolean on_button_release(GtkWidget *, GdkEventButton *, gpointer); -+ -+ void goto_begin(); -+ void goto_end(); -+ TextBufLinks::const_iterator find_link(gint x, gint y); -+}; -+ -+class LabelPangoWidget : public PangoWidgetBase { -+public: -+ LabelPangoWidget(); -+ GtkWidget *widget() { return GTK_WIDGET(label_); } -+ -+ void clear(); -+ void append_mark(const char *mark) {} -+ void append_pixbuf(GdkPixbuf *pixbuf, const char *label); -+ void append_widget(GtkWidget *widget); -+ std::string get_text(); -+ void modify_bg(GtkStateType state, const GdkColor *color); -+protected: -+ void do_set_text(const char *str); -+ void do_append_text(const char *str); -+ void do_append_pango_text(const char *str); -+ void do_set_pango_text(const char *str); -+private: -+ GtkLabel *label_; -+ GtkWidget *viewport_; -+}; -+ -+ -+void PangoWidgetBase::begin_update() -+{ -+ update_ = true; -+} -+ -+void PangoWidgetBase::end_update() -+{ -+ if (update_) { -+ update_ = false; -+ do_append_pango_text(cache_.c_str()); -+ cache_.clear(); -+ } -+} -+ -+void PangoWidgetBase::append_text(const char *str) -+{ -+ if (update_) { -+ gchar *mark = g_markup_escape_text(str, -1); -+ cache_ += mark; -+ g_free(mark); -+ } else { -+ do_append_text(str); -+ } -+} -+ -+void PangoWidgetBase::append_pango_text(const char *str) -+{ -+ if (update_) -+ cache_ += str; -+ else -+ do_append_pango_text(str); -+} -+ -+void PangoWidgetBase::append_pango_text_with_links(const std::string& str, -+ const LinksPosList&) -+{ -+ append_pango_text(str.c_str()); -+} -+ -+void PangoWidgetBase::set_pango_text(const char *str) -+{ -+ if (update_) -+ cache_ = str; -+ else -+ do_set_pango_text(str); -+} -+ -+ -+void TextPangoWidget::begin_update() -+{ -+ PangoWidgetBase::begin_update(); -+ gtk_text_buffer_begin_user_action( -+ gtk_text_view_get_buffer(textview_)); -+} -+ -+ -+void TextPangoWidget::end_update() -+{ -+ PangoWidgetBase::end_update(); -+ gtk_text_buffer_end_user_action(gtk_text_view_get_buffer(textview_)); -+} -+ -+ -+TextPangoWidget::TextPangoWidget() -+{ -+ hand_cursor_.reset(gdk_cursor_new(GDK_HAND2)); -+ regular_cursor_.reset(gdk_cursor_new(GDK_XTERM)); -+ textview_ = GTK_TEXT_VIEW(gtk_text_view_new()); -+ gtk_widget_show(GTK_WIDGET(textview_)); -+ gtk_text_view_set_editable(textview_, FALSE); -+ gtk_text_view_set_cursor_visible(textview_, FALSE); -+ gtk_text_view_set_wrap_mode(textview_, GTK_WRAP_WORD_CHAR); -+ gtk_text_view_set_left_margin(textview_, 5); -+ gtk_text_view_set_right_margin(textview_, 5); -+ -+ g_signal_connect(textview_, "button-release-event", -+ G_CALLBACK(on_button_release), this); -+ g_signal_connect(textview_, "motion-notify-event", -+ G_CALLBACK(on_mouse_move), this); -+ -+ gtk_text_buffer_get_iter_at_offset(gtk_text_view_get_buffer(textview_), -+ &iter_, 0); -+ scroll_win_ = GTK_SCROLLED_WINDOW(gtk_scrolled_window_new(NULL, NULL)); -+ gtk_widget_show(GTK_WIDGET(scroll_win_)); -+ -+ -+ gtk_scrolled_window_set_policy(scroll_win_, -+ //altought textview's set_wrap_mode will cause -+ //this can be GTK_POLICY_NEVER,but... -+ //there are widgets that may make this broken. -+ GTK_POLICY_AUTOMATIC, -+ GTK_POLICY_AUTOMATIC); -+ gtk_container_add(GTK_CONTAINER(scroll_win_), GTK_WIDGET(textview_)); -+ gtk_scrolled_window_set_shadow_type(scroll_win_, GTK_SHADOW_IN); -+} -+ -+void LabelPangoWidget::modify_bg(GtkStateType state, const GdkColor *color) -+{ -+ gtk_widget_modify_bg(viewport_, state, color); -+} -+ -+LabelPangoWidget::LabelPangoWidget() -+{ -+ label_ = GTK_LABEL(gtk_label_new(NULL)); -+ gtk_label_set_justify(label_, GTK_JUSTIFY_LEFT); -+ scroll_win_ = GTK_SCROLLED_WINDOW(gtk_scrolled_window_new(NULL, NULL)); -+ gtk_scrolled_window_set_shadow_type(scroll_win_, GTK_SHADOW_NONE); -+ gtk_scrolled_window_set_policy(scroll_win_, GTK_POLICY_NEVER, -+ GTK_POLICY_AUTOMATIC); -+ -+ viewport_ = -+ gtk_viewport_new(gtk_scrolled_window_get_hadjustment(scroll_win_), -+ gtk_scrolled_window_get_vadjustment(scroll_win_)); -+ gtk_widget_add_events(viewport_, GDK_BUTTON1_MOTION_MASK); -+ gtk_widget_add_events(viewport_, GDK_BUTTON_RELEASE_MASK); -+ gtk_viewport_set_shadow_type(GTK_VIEWPORT(viewport_), GTK_SHADOW_NONE); -+ gtk_container_add(GTK_CONTAINER(scroll_win_), viewport_); -+ gtk_container_add(GTK_CONTAINER(viewport_), GTK_WIDGET(label_)); -+} -+ -+PangoWidgetBase *PangoWidgetBase::create(bool autoresize) -+{ -+ if (!autoresize) -+ return new TextPangoWidget; -+ else -+ return new LabelPangoWidget; -+} -+ -+void TextPangoWidget::do_set_text(const char *text) -+{ -+ GtkTextBuffer *buffer = gtk_text_view_get_buffer(textview_); -+ -+ std::list<GtkTextMark *>::const_iterator it; -+ for (it = marklist_.begin(); it != marklist_.end(); ++it) -+ gtk_text_buffer_delete_mark(buffer, *it); -+ marklist_.clear(); -+ tb_links_.clear(); -+ -+ gtk_text_buffer_set_text(buffer, text, -1); -+} -+ -+void LabelPangoWidget::do_set_text(const char *text) -+{ -+ scroll_to(0); -+ // this should speed up the next two line. -+ gtk_label_set_markup(label_, ""); -+ // so Popup()'s gtk_widget_size_request(label, &requisition); can -+ gtk_widget_set_size_request(GTK_WIDGET(label_), -1, -1); -+ // get its original width. -+ gtk_label_set_line_wrap(label_, FALSE); -+ gchar *mstr = g_markup_escape_text(text, -1); -+ gtk_label_set_text(label_, mstr); -+ g_free(mstr); -+} -+ -+void LabelPangoWidget::append_pixbuf(GdkPixbuf *pixbuf, const char *label) -+{ -+ if (label) { -+ gchar *markup = g_markup_printf_escaped("<span foreground=\"red\">[Image:%s]</span>", label); -+ append_pango_text(markup); -+ g_free(markup); -+ } else { -+ append_pango_text("<span foreground=\"red\">[Image]</span>"); -+ } -+} -+ -+void LabelPangoWidget::append_widget(GtkWidget *widget) -+{ -+ append_pango_text("<span foreground=\"red\">[Widget]</span>"); -+ if (widget) { -+ gtk_widget_destroy(widget); -+ } -+} -+ -+void PangoWidgetBase::set_text(const char *str) -+{ -+ if (update_) { -+ gchar *mark = g_markup_escape_text(str, -1); -+ cache_ = mark; -+ g_free(mark); -+ } else { -+ do_set_text(str); -+ } -+} -+ -+void TextPangoWidget::do_append_text(const char *str) -+{ -+ gtk_text_buffer_insert(gtk_text_view_get_buffer(textview_), -+ &iter_, str, strlen(str)); -+} -+ -+void LabelPangoWidget::do_append_text(const char *str) -+{ -+ set_text((std::string(gtk_label_get_text(label_)) + str).c_str()); -+} -+ -+ -+void TextPangoWidget::do_append_pango_text(const char *str) -+{ -+ -+ gtk_text_buffer_insert_markup(gtk_text_view_get_buffer(textview_), -+ &iter_, str); -+} -+ -+void TextPangoWidget::do_set_pango_text(const char *str) -+{ -+ clear(); -+ goto_begin(); -+ do_append_pango_text(str); -+} -+ -+void LabelPangoWidget::do_set_pango_text(const char *str) -+{ -+ scroll_to(0); -+ // this should speed up the next two line. -+ gtk_label_set_markup(label_, ""); -+ // so Popup()'s gtk_widget_size_request(label,&requisition); can -+ gtk_widget_set_size_request(GTK_WIDGET(label_), -1, -1); -+ // get its original width. -+ gtk_label_set_line_wrap(label_, FALSE); -+ gtk_label_set_markup(label_, str); -+} -+ -+void LabelPangoWidget::do_append_pango_text(const char *str) -+{ -+ do_set_pango_text((std::string(gtk_label_get_label(label_)) + str).c_str()); -+} -+ -+void TextPangoWidget::append_mark(const char *mark) -+{ -+ GtkTextBuffer *buffer=gtk_text_view_get_buffer(textview_); -+ if (update_) { -+ if (!cache_.empty()) { -+ do_append_pango_text(cache_.c_str()); -+ cache_.clear(); -+ } -+ } -+ marklist_.push_back( -+ gtk_text_buffer_create_mark(buffer, mark, &iter_, TRUE)); -+} -+ -+void TextPangoWidget::clear() -+{ -+ GtkTextBuffer *buffer = gtk_text_view_get_buffer(textview_); -+ -+ std::list<GtkTextMark *>::const_iterator it; -+ for (it = marklist_.begin(); it != marklist_.end(); ++it) -+ gtk_text_buffer_delete_mark(buffer, *it); -+ -+ marklist_.clear(); -+ tb_links_.clear(); -+ -+ GtkTextIter start, end; -+ gtk_text_buffer_get_bounds(buffer, &start, &end); -+ gtk_text_buffer_delete(buffer, &start, &end); -+ scroll_to(0); -+ cache_.clear(); -+} -+ -+void LabelPangoWidget::clear() -+{ -+ do_set_text(""); -+ cache_.clear(); -+} -+ -+void TextPangoWidget::goto_begin() -+{ -+ gtk_text_buffer_get_iter_at_offset( -+ gtk_text_view_get_buffer(textview_), &iter_, 0 -+ ); -+} -+ -+void TextPangoWidget::goto_end() -+{ -+ gtk_text_buffer_get_iter_at_offset(gtk_text_view_get_buffer(textview_), &iter_, -1); -+} -+ -+std::string TextPangoWidget::get_text() -+{ -+ std::string res; -+ -+ GtkTextIter start, end; -+ GtkTextBuffer *buffer=gtk_text_view_get_buffer(textview_); -+ gtk_text_buffer_get_bounds(buffer, &start, &end); -+ gchar *text = gtk_text_buffer_get_text(buffer, &start, &end, FALSE); -+ res = text; -+ g_free(text); -+ -+ return res; -+} -+ -+std::string LabelPangoWidget::get_text() -+{ -+ return gtk_label_get_text(label_); -+} -+ -+ -+void TextPangoWidget::append_pango_text_with_links(const std::string& str, -+ const LinksPosList& links) -+{ -+ if (links.empty()) { -+ append_pango_text(str.c_str()); -+ return; -+ } -+ -+ do_append_pango_text(cache_.c_str()); -+ cache_.clear(); -+ -+ gint beg = gtk_text_iter_get_offset(&iter_); -+ -+ for (LinksPosList::const_iterator it = links.begin(); -+ it != links.end(); ++it) { -+ tb_links_.push_back(TextBufPos(beg + it->pos_, beg + it->pos_ + it->len_, it->link_)); -+ } -+ -+ gtk_text_buffer_insert_markup(gtk_text_view_get_buffer(textview_), -+ &iter_, str.c_str()); -+} -+ -+void TextPangoWidget::append_pixbuf(GdkPixbuf *pixbuf, const char *label) -+{ -+ do_append_pango_text(cache_.c_str()); -+ cache_.clear(); -+ gtk_text_buffer_insert_pixbuf (gtk_text_view_get_buffer(textview_), &iter_, pixbuf); -+} -+ -+void TextPangoWidget::append_widget(GtkWidget *widget) -+{ -+ do_append_pango_text(cache_.c_str()); -+ cache_.clear(); -+ GtkTextChildAnchor *anchor = gtk_text_buffer_create_child_anchor (gtk_text_view_get_buffer(textview_), &iter_); -+ gtk_text_view_add_child_at_anchor (textview_, widget, anchor); -+} -+ -+TextPangoWidget::TextBufLinks::const_iterator TextPangoWidget::find_link(gint x, -+ gint y) -+{ -+ GtkTextIter iter; -+ gtk_text_view_get_iter_at_location(textview_, &iter, x, y); -+ gint pos = gtk_text_iter_get_offset(&iter); -+ TextBufLinks::const_iterator it; -+ for (it = tb_links_.begin(); it != tb_links_.end(); ++it) { -+ if (pos < it->beg_) -+ return tb_links_.end(); -+ if (it->beg_ <= pos && pos < it->end_) -+ break; -+ } -+ return it; -+} -+ -+gboolean TextPangoWidget::on_mouse_move(GtkWidget *widget, GdkEventMotion *event, -+ gpointer userdata) -+{ -+ TextPangoWidget *tpw = static_cast<TextPangoWidget *>(userdata); -+ GtkTextWindowType win_type = -+ gtk_text_view_get_window_type(tpw->textview_, event->window); -+ gint x, y; -+ gtk_text_view_window_to_buffer_coords(tpw->textview_, win_type, -+ gint(event->x), gint(event->y), -+ &x, &y); -+ -+ TextBufLinks::const_iterator it = tpw->find_link(x, y); -+ if (it != tpw->tb_links_.end()) { -+ gdk_window_set_cursor( -+ gtk_text_view_get_window(tpw->textview_, -+ GTK_TEXT_WINDOW_TEXT), -+ get_impl(tpw->hand_cursor_)); -+ } else { -+ gdk_window_set_cursor( -+ gtk_text_view_get_window(tpw->textview_, -+ GTK_TEXT_WINDOW_TEXT), -+ get_impl(tpw->regular_cursor_)); -+ } -+ -+ gdk_window_get_pointer(widget->window, NULL, NULL, NULL); -+ -+ return FALSE; -+} -+ -+ -+ -+gboolean TextPangoWidget::on_button_release(GtkWidget *, GdkEventButton *event, -+ gpointer userdata) -+{ -+ if (event->button != 1) -+ return FALSE; -+ TextPangoWidget *tpw = static_cast<TextPangoWidget *>(userdata); -+ GtkTextBuffer *buf = gtk_text_view_get_buffer(tpw->textview_); -+ /* we shouldn't follow a link if the user has selected something */ -+ GtkTextIter beg, end; -+ gtk_text_buffer_get_selection_bounds (buf, &beg, &end); -+ if (gtk_text_iter_get_offset (&beg) != gtk_text_iter_get_offset (&end)) -+ return FALSE; -+ GtkTextWindowType win_type = -+ gtk_text_view_get_window_type(tpw->textview_, event->window); -+ gint x, y; -+ gtk_text_view_window_to_buffer_coords(tpw->textview_, win_type, -+ gint(event->x), gint(event->y), -+ &x, &y); -+ TextBufLinks::const_iterator it = tpw->find_link(x, y); -+ if (it != tpw->tb_links_.end()) { -+ tpw->on_link_click_.emit(it->link_); -+ } -+ return FALSE; -+} -diff -Nur stardict-3.0.1.orig//src/prefsdlg.cpp stardict-3.0.1/src/prefsdlg.cpp ---- stardict-3.0.1.orig//src/prefsdlg.cpp 2007-10-30 03:14:07.000000000 -0500 -+++ stardict-3.0.1/src/prefsdlg.cpp 2010-05-24 00:53:36.380667202 -0500 -@@ -21,6 +21,8 @@ - # include "config.h" - #endif - -+#include <cstdlib> -+ - #include <glib/gi18n.h> - #include <glib/gstdio.h> - -diff -Nur stardict-3.0.1.orig//src/prefsdlg.cpp~ stardict-3.0.1/src/prefsdlg.cpp~ ---- stardict-3.0.1.orig//src/prefsdlg.cpp~ 1969-12-31 18:00:00.000000000 -0600 -+++ stardict-3.0.1/src/prefsdlg.cpp~ 2007-10-30 03:14:07.000000000 -0500 -@@ -0,0 +1,1908 @@ -+/* -+ * This file part of StarDict - A international dictionary for GNOME. -+ * http://stardict.sourceforge.net -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 3 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU Library General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -+ */ -+ -+#ifdef HAVE_CONFIG_H -+# include "config.h" -+#endif -+ -+#include <glib/gi18n.h> -+#include <glib/gstdio.h> -+ -+#ifdef _WIN32 -+# include <gdk/gdkwin32.h> -+#endif -+ -+#include "stardict.h" -+#include "conf.h" -+#include "desktop.hpp" -+#include "utils.h" -+#include "iskeyspressed.hpp" -+#include "lib/md5.h" -+ -+#include "prefsdlg.h" -+ -+#ifndef CONFIG_GPE -+enum { -+ LOGO = 0, -+ DICTIONARY_SCAN_SETTINGS, -+ DICTIONARY_FONT_SETTINGS, -+ DICTIONARY_CACHE_SETTINGS, -+ DICTIONARY_EXPORT_SETTINGS, -+ DICTIONARY_SOUND_SETTINGS, -+ DICIONARY_ARTICLE_RENDERING, -+ NETWORK_NETDICT, -+ MAINWIN_INPUT_SETTINGS, -+ MAINWIN_OPTIONS_SETTINGS, -+ MAINWIN_SEARCH_WEBSITE_SETTINGS, -+ NOTIFICATION_AREA_ICON_OPITIONS_SETTINGS, -+ FLOATWIN_OPTIONS_SETTINGS, -+ FLOATWIN_SIZE_SETTINGS, -+}; -+ -+enum -+{ -+ CATEGORY_COLUMN = 0, -+ PAGE_NUM_COLUMN, -+ NUM_COLUMNS -+}; -+ -+ -+struct CategoriesTreeItem { -+ gchar *category; -+ -+ CategoriesTreeItem *children; -+ -+ gint notebook_page; -+}; -+ -+static CategoriesTreeItem dictionary_behavior [] = { -+ {N_("Scan Selection"), NULL, DICTIONARY_SCAN_SETTINGS}, -+ {N_("Font"), NULL, DICTIONARY_FONT_SETTINGS}, -+ {N_("Cache"), NULL, DICTIONARY_CACHE_SETTINGS}, -+ {N_("Export"), NULL, DICTIONARY_EXPORT_SETTINGS}, -+ {N_("Sound"), NULL, DICTIONARY_SOUND_SETTINGS}, -+ {N_("Article rendering"), NULL, DICIONARY_ARTICLE_RENDERING }, -+ { NULL } -+}; -+ -+static CategoriesTreeItem network_behavior [] = { -+ {N_("Net Dict"), NULL, NETWORK_NETDICT}, -+ { NULL } -+}; -+ -+static CategoriesTreeItem mainwin_behavior [] = -+{ -+ {N_("Input"), NULL, MAINWIN_INPUT_SETTINGS}, -+ {N_("Options"), NULL, MAINWIN_OPTIONS_SETTINGS}, -+ {N_("Search website"), NULL, MAINWIN_SEARCH_WEBSITE_SETTINGS}, -+ -+ { NULL } -+}; -+ -+static CategoriesTreeItem NotificationAreaIcon_behavior [] = -+{ -+ {N_("Options"), NULL, NOTIFICATION_AREA_ICON_OPITIONS_SETTINGS}, -+ -+ { NULL } -+}; -+ -+static CategoriesTreeItem floatwin_behavior [] = -+{ -+ {N_("Options"), NULL, FLOATWIN_OPTIONS_SETTINGS}, -+ {N_("Settings"), NULL, FLOATWIN_SIZE_SETTINGS}, -+ -+ { NULL } -+}; -+ -+static CategoriesTreeItem toplevel [] = -+{ -+ {N_("Dictionary"), dictionary_behavior, LOGO}, -+ -+ {N_("Network"), network_behavior, LOGO}, -+ -+ {N_("Main window"), mainwin_behavior, LOGO}, -+ -+ {N_("Notification area icon"), NotificationAreaIcon_behavior, LOGO}, -+ -+ {N_("Floating window"), floatwin_behavior, LOGO}, -+ -+ { NULL } -+}; -+ -+static gint last_selected_page_num = DICTIONARY_SCAN_SETTINGS; -+#endif -+ -+void PrefsDlg::response_handler (GtkDialog *dialog, gint res_id, PrefsDlg *oPrefsDlg) -+{ -+ if (res_id==GTK_RESPONSE_HELP) -+ show_help("stardict-prefs"); -+} -+ -+#ifndef CONFIG_GPE -+GtkTreeModel* PrefsDlg::create_categories_tree_model () -+{ -+ GtkTreeStore *model; -+ GtkTreeIter iter; -+ CategoriesTreeItem *category = toplevel; -+ -+ model = gtk_tree_store_new (NUM_COLUMNS, G_TYPE_STRING, G_TYPE_INT); -+ -+ while (category->category) { -+ CategoriesTreeItem *sub_category = category->children; -+ gtk_tree_store_append (model, &iter, NULL); -+ gtk_tree_store_set (model, &iter, CATEGORY_COLUMN, gettext (category->category), PAGE_NUM_COLUMN, category->notebook_page, -1); -+ -+ while (sub_category->category) { -+ GtkTreeIter child_iter; -+ gtk_tree_store_append (model, &child_iter, &iter); -+ gtk_tree_store_set (model, &child_iter, -+ CATEGORY_COLUMN, gettext (sub_category->category), -+ PAGE_NUM_COLUMN, sub_category->notebook_page, -+ -1); -+ sub_category++; -+ } -+ category++; -+ } -+ return GTK_TREE_MODEL (model); -+} -+ -+void PrefsDlg::categories_tree_selection_cb (GtkTreeSelection *selection, PrefsDlg *oPrefsDlg) -+{ -+ GtkTreeIter iter; -+ GValue value = {0, }; -+ -+ if (! gtk_tree_selection_get_selected (selection, NULL, &iter)) -+ return; -+ -+ gtk_tree_model_get_value (oPrefsDlg->categories_tree_model, &iter, -+ PAGE_NUM_COLUMN, -+ &value); -+ -+ last_selected_page_num = g_value_get_int (&value); -+ -+ if (oPrefsDlg->notebook != NULL) -+ gtk_notebook_set_current_page (GTK_NOTEBOOK (oPrefsDlg->notebook), -+ last_selected_page_num); -+ g_value_unset (&value); -+} -+ -+gboolean PrefsDlg::selection_init (GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, PrefsDlg *oPrefsDlg) -+{ -+ GValue value = {0, }; -+ gint page_num; -+ -+ gtk_tree_model_get_value (oPrefsDlg->categories_tree_model, iter, -+ PAGE_NUM_COLUMN, -+ &value); -+ -+ page_num = g_value_get_int (&value); -+ -+ g_value_unset (&value); -+ -+ if (page_num == last_selected_page_num) -+ { -+ GtkTreeSelection *selection; -+ -+ selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (oPrefsDlg->categories_tree)); -+ -+ gtk_tree_selection_select_iter (selection, iter); -+ -+ gtk_notebook_set_current_page (GTK_NOTEBOOK (oPrefsDlg->notebook), page_num); -+ -+ return TRUE; -+ } -+ return FALSE; -+} -+ -+void PrefsDlg::categories_tree_realize (GtkWidget *widget, PrefsDlg *oPrefsDlg) -+{ -+ gtk_tree_view_expand_all(GTK_TREE_VIEW(widget)); -+ -+ gtk_tree_model_foreach(oPrefsDlg->categories_tree_model, -+ GtkTreeModelForeachFunc(selection_init), -+ oPrefsDlg); -+} -+ -+void PrefsDlg::create_categories_tree(void) -+{ -+ GtkWidget *sw; -+ GtkTreeModel *model; -+ GtkWidget *treeview; -+ GtkCellRenderer *renderer; -+ GtkTreeSelection *selection; -+ GtkTreeViewColumn *column; -+ gint col_offset; -+ -+ sw = gtk_scrolled_window_new (NULL, NULL); -+ gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (sw), -+ GTK_SHADOW_ETCHED_IN); -+ gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw), -+ GTK_POLICY_AUTOMATIC, -+ GTK_POLICY_AUTOMATIC); -+ -+ gtk_widget_set_size_request (sw, 140, 240); -+ -+ model = create_categories_tree_model (); -+ -+ treeview = gtk_tree_view_new_with_model (model); -+ g_object_unref (G_OBJECT (model)); -+ gtk_tree_view_set_rules_hint (GTK_TREE_VIEW (treeview), TRUE); -+ -+ categories_tree = treeview; -+ categories_tree_model = model; -+ -+ selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (treeview)); -+ -+ gtk_tree_selection_set_mode (selection, -+ GTK_SELECTION_SINGLE); -+ -+ /* add column for category */ -+ renderer = gtk_cell_renderer_text_new (); -+ g_object_set (G_OBJECT (renderer), "xalign", 0.0, NULL); -+ -+ col_offset = gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (treeview), -+ -1, _("Categories"), -+ renderer, "text", -+ CATEGORY_COLUMN, -+ NULL); -+ -+ column = gtk_tree_view_get_column (GTK_TREE_VIEW (treeview), col_offset - 1); -+ gtk_tree_view_column_set_clickable (GTK_TREE_VIEW_COLUMN (column), FALSE); -+ -+ g_signal_connect (selection, "changed", -+ G_CALLBACK (categories_tree_selection_cb), -+ this); -+ -+ gtk_container_add (GTK_CONTAINER (sw), treeview); -+ -+ g_signal_connect (G_OBJECT (treeview), "realize", -+ G_CALLBACK (categories_tree_realize), -+ this); -+ -+ gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (treeview), FALSE); -+ -+ categories_window=sw; -+} -+ -+void PrefsDlg::setup_logo_page() -+{ -+ GtkWidget *image = gtk_image_new_from_pixbuf(stardict_logo); -+ gtk_notebook_append_page(GTK_NOTEBOOK(notebook),image,NULL); -+} -+#endif -+ -+static GtkWidget *prepare_page(GtkNotebook *notebook, const gchar *caption, -+ const gchar *stock_id) -+{ -+ GtkWidget *vbox = gtk_vbox_new(FALSE, 12); -+#ifdef CONFIG_GPE -+ gtk_container_set_border_width(GTK_CONTAINER (vbox), 5); -+ GtkWidget *nb_label = gtk_label_new(caption); -+ gtk_notebook_append_page(notebook, vbox, nb_label); -+#else -+ gtk_notebook_append_page(notebook, vbox, NULL); -+#endif -+ -+ GtkWidget *vbox1 = gtk_vbox_new(FALSE, 6); -+ gtk_box_pack_start(GTK_BOX(vbox), vbox1, FALSE, FALSE, 6); -+ GtkWidget *hbox = gtk_hbox_new(FALSE, 6); -+ gtk_box_pack_start(GTK_BOX(vbox1), hbox, FALSE, FALSE, 0); -+ GtkWidget *image = -+ gtk_image_new_from_stock(stock_id, -+ GTK_ICON_SIZE_LARGE_TOOLBAR); -+ gtk_box_pack_start(GTK_BOX(hbox), image, FALSE, FALSE, 0); -+ GtkWidget *label = gtk_label_new(NULL); -+ glib::CharStr label_caption( -+ g_markup_printf_escaped("<span weight=\"bold\" size=\"x-large\">%s</span>", caption)); -+ gtk_label_set_markup(GTK_LABEL(label), get_impl(label_caption)); -+ gtk_box_pack_start(GTK_BOX(hbox),label, FALSE, FALSE, 0); -+ GtkWidget *hseparator = gtk_hseparator_new(); -+ gtk_box_pack_start(GTK_BOX(vbox1),hseparator,FALSE,FALSE,0); -+ -+ return vbox; -+} -+ -+void PrefsDlg::on_setup_dictionary_scan_ckbutton_toggled(GtkToggleButton *button, PrefsDlg *oPrefsDlg) -+{ -+ gboolean b = gtk_toggle_button_get_active(button); -+ gtk_widget_set_sensitive(oPrefsDlg->scan_modifier_key_vbox,b); -+ conf->set_bool_at("dictionary/only_scan_while_modifier_key", b); -+} -+ -+#ifdef _WIN32 -+void PrefsDlg::on_setup_dictionary_scan_clipboard_ckbutton_toggled(GtkToggleButton *button, PrefsDlg *oPrefsDlg) -+{ -+ gboolean b = gtk_toggle_button_get_active(button); -+ if (b) { -+ if (conf->get_bool_at("dictionary/scan_selection")) -+ gpAppFrame->oClipboard.start(); -+ } else { -+ if (conf->get_bool_at("dictionary/scan_selection")) -+ gpAppFrame->oClipboard.stop(); -+ } -+ conf->set_bool_at("dictionary/scan_clipboard", b); -+} -+ -+void PrefsDlg::on_setup_dictionary_use_scan_hotkey_ckbutton_toggled(GtkToggleButton *button, PrefsDlg *oPrefsDlg) -+{ -+ gboolean b = gtk_toggle_button_get_active(button); -+ if (b) -+ gpAppFrame->oHotkey.start_scan(); -+ else -+ gpAppFrame->oHotkey.stop_scan(); -+ conf->set_bool_at("dictionary/use_scan_hotkey", b); -+} -+#endif -+ -+void PrefsDlg::on_setup_dictionary_scan_combobox_changed(GtkComboBox *combobox, PrefsDlg *oPrefsDlg) -+{ -+ gint key = gtk_combo_box_get_active(combobox); -+ conf->set_int_at("dictionary/scan_modifier_key", key); -+} -+ -+void PrefsDlg::on_setup_dictionary_scan_hide_ckbutton_toggled(GtkToggleButton *button, PrefsDlg *oPrefsDlg) -+{ -+ gboolean hide = gtk_toggle_button_get_active(button); -+ conf->set_bool_at("dictionary/hide_floatwin_when_modifier_key_released", hide); -+} -+ -+void PrefsDlg::setup_dictionary_scan_page() -+{ -+ GtkWidget *vbox = prepare_page(GTK_NOTEBOOK(notebook), _("Scan Selection"), GTK_STOCK_CONVERT); -+ GtkWidget *vbox1 = gtk_vbox_new(false, 0); -+ gtk_box_pack_start(GTK_BOX(vbox),vbox1,false,false, 0); -+ GtkWidget *check_button = gtk_check_button_new_with_mnemonic(_("_Only scan while the modifier key is being pressed.")); -+ gtk_box_pack_start(GTK_BOX(vbox1),check_button,false,false,0); -+ bool only_scan_while_modifier_key= -+ conf->get_bool_at("dictionary/only_scan_while_modifier_key"); -+ -+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(check_button), -+ only_scan_while_modifier_key); -+ g_signal_connect(G_OBJECT(check_button), "toggled", -+ G_CALLBACK(on_setup_dictionary_scan_ckbutton_toggled), this); -+ -+ scan_modifier_key_vbox = gtk_vbox_new(FALSE, 6); -+ gtk_box_pack_start(GTK_BOX(vbox1), scan_modifier_key_vbox, -+ FALSE, FALSE, 12); -+ gtk_widget_set_sensitive(scan_modifier_key_vbox, -+ only_scan_while_modifier_key); -+ -+ check_button = gtk_check_button_new_with_mnemonic(_("H_ide floating window when modifier key released.")); -+ gtk_box_pack_start(GTK_BOX(scan_modifier_key_vbox),check_button,false,false,0); -+ -+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(check_button), -+ conf->get_bool_at("dictionary/hide_floatwin_when_modifier_key_released")); -+ g_signal_connect (G_OBJECT (check_button), "toggled", G_CALLBACK (on_setup_dictionary_scan_hide_ckbutton_toggled), this); -+ -+ GtkWidget *hbox = gtk_hbox_new(false, 12); -+ gtk_box_pack_start(GTK_BOX(scan_modifier_key_vbox), hbox,false,false,0); -+ GtkWidget *label=gtk_label_new(NULL); -+ gtk_label_set_markup_with_mnemonic(GTK_LABEL(label), _("Scan modifier _key:")); -+ gtk_box_pack_start(GTK_BOX(hbox),label,false,false,0); -+ gtk_misc_set_alignment (GTK_MISC (label), 0, .5); -+ GtkWidget *combobox = gtk_combo_box_new_text(); -+ gtk_combo_box_set_focus_on_click(GTK_COMBO_BOX(combobox), FALSE); -+ -+ for (std::list<std::string>::const_iterator p=key_combs.begin(); -+ p!=key_combs.end(); ++p) { -+ gtk_combo_box_append_text(GTK_COMBO_BOX(combobox), p->c_str()); -+ } -+ -+ int scan_modifier_key= -+ conf->get_int_at("dictionary/scan_modifier_key"); -+ -+ gtk_combo_box_set_active(GTK_COMBO_BOX(combobox), scan_modifier_key); -+ -+ gtk_label_set_mnemonic_widget(GTK_LABEL(label), combobox); -+ gtk_box_pack_start(GTK_BOX(hbox), combobox, FALSE, FALSE, 0); -+ g_signal_connect (G_OBJECT (combobox), "changed", G_CALLBACK (on_setup_dictionary_scan_combobox_changed), this); -+ -+#ifdef _WIN32 -+ check_button = gtk_check_button_new_with_mnemonic(_("_Scan clipboard.")); -+ gtk_box_pack_start(GTK_BOX(vbox1),check_button,false,false,0); -+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(check_button), conf->get_bool_at("dictionary/scan_clipboard")); -+ g_signal_connect(G_OBJECT(check_button), "toggled", -+ G_CALLBACK(on_setup_dictionary_scan_clipboard_ckbutton_toggled), this); -+ -+ check_button = gtk_check_button_new_with_mnemonic(_("_Use scan hotkey: Ctrl+Alt+F1.")); -+ gtk_box_pack_start(GTK_BOX(vbox1),check_button,false,false,0); -+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(check_button), conf->get_bool_at("dictionary/use_scan_hotkey")); -+ g_signal_connect(G_OBJECT(check_button), "toggled", -+ G_CALLBACK(on_setup_dictionary_use_scan_hotkey_ckbutton_toggled), this); -+#endif -+} -+ -+void PrefsDlg::change_font_for_all_widgets(const std::string& fontname) -+{ -+ gchar *aa = -+ g_strdup_printf("style \"custom-font\" { font_name= \"%s\" }\n" -+ "class \"GtkWidget\" style \"custom-font\"\n", fontname.c_str()); -+ gtk_rc_parse_string(aa); -+ g_free(aa); -+ GdkScreen *screen = gtk_window_get_screen(parent_window); -+ GtkSettings *settings=gtk_settings_get_for_screen(screen); -+ gtk_rc_reset_styles(settings); -+#ifndef CONFIG_GPE -+ resize_categories_tree(); -+#endif -+} -+ -+void PrefsDlg::on_setup_dictionary_font_ckbutton_toggled(GtkToggleButton *button, PrefsDlg *oPrefsDlg) -+{ -+ gboolean b = gtk_toggle_button_get_active(button); -+ gtk_widget_set_sensitive(oPrefsDlg->custom_font_hbox, b); -+ conf->set_bool_at("dictionary/use_custom_font", b); -+ if (b) { -+ const std::string &custom_font= -+ conf->get_string_at("dictionary/custom_font"); -+ oPrefsDlg->change_font_for_all_widgets(custom_font); -+ } else -+ oPrefsDlg->change_font_for_all_widgets(""); -+} -+ -+void PrefsDlg::on_setup_dictionary_font_button_clicked(GtkWidget *widget, PrefsDlg *oPrefsDlg) -+{ -+ GtkWidget *dlg = gtk_font_selection_dialog_new(_("Choose dictionary font")); -+ gtk_window_set_transient_for (GTK_WINDOW (dlg), GTK_WINDOW (oPrefsDlg->window)); -+ const gchar *text = gtk_button_get_label(GTK_BUTTON(widget)); -+ if (strcmp(text,_("Choose"))) -+ gtk_font_selection_dialog_set_font_name(GTK_FONT_SELECTION_DIALOG(dlg), text); -+ gtk_font_selection_dialog_set_preview_text(GTK_FONT_SELECTION_DIALOG(dlg),_("Dictionary font")); -+ gint result = gtk_dialog_run (GTK_DIALOG (dlg)); -+ if (result==GTK_RESPONSE_OK) { -+ gchar *font_name = -+ gtk_font_selection_dialog_get_font_name(GTK_FONT_SELECTION_DIALOG(dlg)); -+ if (font_name) { -+ gtk_button_set_label(GTK_BUTTON(widget),font_name); -+ conf->set_string_at("dictionary/custom_font", std::string(font_name)); -+ } -+ if (font_name && font_name[0]) { -+ oPrefsDlg->change_font_for_all_widgets(font_name); -+ } -+ } -+ gtk_widget_destroy (dlg); -+} -+ -+void PrefsDlg::setup_dictionary_font_page() -+{ -+ GtkWidget *vbox = prepare_page(GTK_NOTEBOOK(notebook), _("Font"), GTK_STOCK_SELECT_FONT); -+ GtkWidget *vbox1 = gtk_vbox_new(false,6); -+ gtk_box_pack_start(GTK_BOX(vbox),vbox1,false,false, 0); -+ GtkWidget *check_button = gtk_check_button_new_with_mnemonic(_("_Use custom font.")); -+ gtk_box_pack_start(GTK_BOX(vbox1),check_button,false,false,0); -+ bool use_custom_font= -+ conf->get_bool_at("dictionary/use_custom_font"); -+ -+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(check_button), -+ use_custom_font); -+ g_signal_connect (G_OBJECT (check_button), "toggled", G_CALLBACK (on_setup_dictionary_font_ckbutton_toggled), this); -+ custom_font_hbox = gtk_hbox_new(false, 12); -+ gtk_box_pack_start(GTK_BOX(vbox1),custom_font_hbox,false,false,0); -+ gtk_widget_set_sensitive(custom_font_hbox, use_custom_font); -+ GtkWidget *label=gtk_label_new(NULL); -+ gtk_label_set_markup_with_mnemonic(GTK_LABEL(label), _("Dictionary _font:")); -+ gtk_box_pack_start(GTK_BOX(custom_font_hbox),label,false,false,0); -+ gtk_misc_set_alignment (GTK_MISC (label), 0, .5); -+ GtkWidget *button; -+ const std::string &custom_font= -+ conf->get_string_at("dictionary/custom_font"); -+ -+ if (!custom_font.empty()) -+ button = gtk_button_new_with_label(custom_font.c_str()); -+ else -+ button=gtk_button_new_with_label(_("Choose")); -+ -+ gtk_label_set_mnemonic_widget(GTK_LABEL(label), button); -+ gtk_box_pack_start(GTK_BOX(custom_font_hbox),button,false,false,0); -+ g_signal_connect (G_OBJECT (button), "clicked", G_CALLBACK (on_setup_dictionary_font_button_clicked), this); -+} -+ -+void PrefsDlg::on_setup_dictionary_cache_CreateCacheFile_ckbutton_toggled(GtkToggleButton *button, PrefsDlg *oPrefsDlg) -+{ -+ gboolean enable = gtk_toggle_button_get_active(button); -+ conf->set_bool_at("dictionary/create_cache_file",enable); -+} -+ -+void PrefsDlg::on_setup_dictionary_cache_EnableCollation_ckbutton_toggled(GtkToggleButton *button, PrefsDlg *oPrefsDlg) -+{ -+ gboolean enable = gtk_toggle_button_get_active(button); -+ gtk_widget_set_sensitive(oPrefsDlg->collation_hbox, enable); -+ conf->set_bool_at("dictionary/enable_collation",enable); -+} -+ -+void PrefsDlg::on_setup_dictionary_collation_combobox_changed(GtkComboBox *combobox, PrefsDlg *oPrefsDlg) -+{ -+ gint key = gtk_combo_box_get_active(combobox); -+ conf->set_int_at("dictionary/collate_function", key); -+} -+ -+static void clean_dir(const gchar *dirname) -+{ -+ GDir *dir = g_dir_open(dirname, 0, NULL); -+ if (dir) { -+ const gchar *filename; -+ gchar fullfilename[256]; -+ while ((filename = g_dir_read_name(dir))!=NULL) { -+ sprintf(fullfilename, "%s" G_DIR_SEPARATOR_S "%s", dirname, filename); -+ if (g_file_test(fullfilename, G_FILE_TEST_IS_DIR)) { -+ clean_dir(fullfilename); -+ } else if (g_str_has_suffix(filename,".oft") || g_str_has_suffix(filename,".clt")) { -+ g_unlink(fullfilename); -+ } -+ } -+ g_dir_close(dir); -+ } -+} -+ -+void PrefsDlg::on_setup_dictionary_cache_cleanbutton_clicked(GtkWidget *widget, PrefsDlg *oPrefsDlg) -+{ -+ std::string dirname = gStarDictDataDir+ G_DIR_SEPARATOR_S "dic"; -+ clean_dir(dirname.c_str()); -+ dirname = g_get_user_cache_dir(); -+ dirname += G_DIR_SEPARATOR_S "stardict"; -+ clean_dir(dirname.c_str()); -+ g_rmdir(dirname.c_str()); -+} -+ -+void PrefsDlg::setup_dictionary_cache_page() -+{ -+ GtkWidget *vbox = prepare_page(GTK_NOTEBOOK(notebook), _("Cache"), GTK_STOCK_HARDDISK); -+ GtkWidget *vbox1 = gtk_vbox_new(false, 6); -+ gtk_box_pack_start(GTK_BOX(vbox),vbox1,false,false, 0); -+ GtkWidget *check_button; -+ check_button = gtk_check_button_new_with_mnemonic(_("Create c_ache files to speed up loading.")); -+ bool enable = conf->get_bool_at("dictionary/create_cache_file"); -+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(check_button), enable); -+ g_signal_connect (G_OBJECT (check_button), "toggled", G_CALLBACK (on_setup_dictionary_cache_CreateCacheFile_ckbutton_toggled), (gpointer)this); -+ gtk_box_pack_start(GTK_BOX(vbox1),check_button,false,false,0); -+ check_button = gtk_check_button_new_with_mnemonic(_("_Sort word list by collation function.")); -+ enable = conf->get_bool_at("dictionary/enable_collation"); -+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(check_button), enable); -+ g_signal_connect (G_OBJECT (check_button), "toggled", G_CALLBACK (on_setup_dictionary_cache_EnableCollation_ckbutton_toggled), (gpointer)this); -+ gtk_box_pack_start(GTK_BOX(vbox1),check_button,false,false,0); -+ collation_hbox = gtk_hbox_new(false,6); -+ gtk_box_pack_start(GTK_BOX(vbox1),collation_hbox,false,false,0); -+ GtkWidget *label=gtk_label_new(NULL); -+ gtk_misc_set_alignment (GTK_MISC (label), 0, .5); -+ gtk_label_set_markup_with_mnemonic(GTK_LABEL(label), _("\tCollation _function:")); -+ gtk_box_pack_start(GTK_BOX(collation_hbox),label,false,false,0); -+ GtkWidget *combobox = gtk_combo_box_new_text(); -+ gtk_combo_box_set_focus_on_click(GTK_COMBO_BOX(combobox), FALSE); -+ gtk_combo_box_append_text(GTK_COMBO_BOX(combobox), "utf8_general_ci"); -+ gtk_combo_box_append_text(GTK_COMBO_BOX(combobox), "utf8_unicode_ci"); -+ gtk_combo_box_append_text(GTK_COMBO_BOX(combobox), "utf8_bin"); -+ gtk_combo_box_append_text(GTK_COMBO_BOX(combobox), "utf8_czech_ci"); -+ gtk_combo_box_append_text(GTK_COMBO_BOX(combobox), "utf8_danish_ci"); -+ gtk_combo_box_append_text(GTK_COMBO_BOX(combobox), "utf8_esperanto_ci"); -+ gtk_combo_box_append_text(GTK_COMBO_BOX(combobox), "utf8_estonian_ci"); -+ gtk_combo_box_append_text(GTK_COMBO_BOX(combobox), "utf8_hungarian_ci"); -+ gtk_combo_box_append_text(GTK_COMBO_BOX(combobox), "utf8_icelandic_ci"); -+ gtk_combo_box_append_text(GTK_COMBO_BOX(combobox), "utf8_latvian_ci"); -+ gtk_combo_box_append_text(GTK_COMBO_BOX(combobox), "utf8_lithuanian_ci"); -+ gtk_combo_box_append_text(GTK_COMBO_BOX(combobox), "utf8_persian_ci"); -+ gtk_combo_box_append_text(GTK_COMBO_BOX(combobox), "utf8_polish_ci"); -+ gtk_combo_box_append_text(GTK_COMBO_BOX(combobox), "utf8_roman_ci"); -+ gtk_combo_box_append_text(GTK_COMBO_BOX(combobox), "utf8_romanian_ci"); -+ gtk_combo_box_append_text(GTK_COMBO_BOX(combobox), "utf8_slovak_ci"); -+ gtk_combo_box_append_text(GTK_COMBO_BOX(combobox), "utf8_slovenian_ci"); -+ gtk_combo_box_append_text(GTK_COMBO_BOX(combobox), "utf8_spanish_ci"); -+ gtk_combo_box_append_text(GTK_COMBO_BOX(combobox), "utf8_spanish2_ci"); -+ gtk_combo_box_append_text(GTK_COMBO_BOX(combobox), "utf8_swedish_ci"); -+ gtk_combo_box_append_text(GTK_COMBO_BOX(combobox), "utf8_turkish_ci"); -+ int collate_function = conf->get_int_at("dictionary/collate_function"); -+ gtk_combo_box_set_active(GTK_COMBO_BOX(combobox), collate_function); -+ gtk_label_set_mnemonic_widget(GTK_LABEL(label), combobox); -+ gtk_box_pack_start(GTK_BOX(collation_hbox), combobox, FALSE, FALSE, 0); -+ g_signal_connect (G_OBJECT (combobox), "changed", G_CALLBACK (on_setup_dictionary_collation_combobox_changed), this); -+ gtk_widget_set_sensitive(collation_hbox, enable); -+ -+ label = gtk_label_new(_("After enabled collation, when load the dictionaries for the first time, it will take some time for sorting, please wait for a moment.")); -+ gtk_label_set_line_wrap(GTK_LABEL(label), TRUE); -+ gtk_box_pack_start(GTK_BOX(vbox1),label,false,false,0); -+ -+ GtkWidget *hbox = gtk_hbox_new(false,6); -+ gtk_box_pack_start(GTK_BOX(vbox1),hbox,false,false,0); -+ GtkWidget *button = gtk_button_new_with_mnemonic(_("C_lean all cache files")); -+ gtk_button_set_image(GTK_BUTTON(button), gtk_image_new_from_stock(GTK_STOCK_CLEAR, GTK_ICON_SIZE_BUTTON)); -+ gtk_box_pack_end(GTK_BOX(hbox),button,false,false,0); -+ g_signal_connect (G_OBJECT (button), "clicked", G_CALLBACK (on_setup_dictionary_cache_cleanbutton_clicked), this); -+} -+ -+ -+ -+void PrefsDlg::on_setup_dictionary_export_ckbutton_toggled(GtkToggleButton *button, PrefsDlg *oPrefsDlg) -+{ -+ gboolean enable = gtk_toggle_button_get_active(button); -+ conf->set_bool_at("dictionary/only_export_word", enable); -+} -+ -+void PrefsDlg::on_setup_dictionary_export_browse_button_clicked(GtkButton *button, PrefsDlg *oPrefsDlg) -+{ -+ GtkWidget *dialog; -+ dialog = gtk_file_chooser_dialog_new (_("Open file..."), -+ GTK_WINDOW(oPrefsDlg->window), -+ GTK_FILE_CHOOSER_ACTION_OPEN, -+ GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, -+ GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT, -+ NULL); -+ gtk_file_chooser_set_filename(GTK_FILE_CHOOSER (dialog), gtk_entry_get_text(oPrefsDlg->eExportFile)); -+ if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT) { -+ gchar *filename; -+ filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog)); -+ gtk_entry_set_text(oPrefsDlg->eExportFile, filename); -+ g_free (filename); -+ } -+ gtk_widget_destroy (dialog); -+} -+ -+void PrefsDlg::setup_dictionary_export_page() -+{ -+ GtkWidget *vbox = prepare_page(GTK_NOTEBOOK(notebook), _("Export"), GTK_STOCK_SAVE); -+ GtkWidget *vbox1 = gtk_vbox_new(false, 6); -+ gtk_box_pack_start(GTK_BOX(vbox),vbox1,false,false, 0); -+ -+ GtkWidget *check_button; -+ check_button = gtk_check_button_new_with_mnemonic(_("_Only export words.")); -+ bool enable= conf->get_bool_at("dictionary/only_export_word"); -+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(check_button), enable); -+ g_signal_connect (G_OBJECT (check_button), "toggled", G_CALLBACK (on_setup_dictionary_export_ckbutton_toggled), this); -+ gtk_box_pack_start(GTK_BOX(vbox1),check_button,false,false,0); -+ -+ GtkWidget *hbox1 = gtk_hbox_new(FALSE, 6); -+ GtkWidget *label=gtk_label_new(_("File name:")); -+ gtk_box_pack_start(GTK_BOX(hbox1), label, FALSE, FALSE, 0); -+ GtkWidget *e = gtk_entry_new(); -+ const std::string &exportfile= conf->get_string_at("dictionary/export_file"); -+ gtk_entry_set_text(GTK_ENTRY(e), exportfile.c_str()); -+ gtk_box_pack_start(GTK_BOX(hbox1), e, TRUE, TRUE, 0); -+ eExportFile=GTK_ENTRY(e); -+ -+ GtkWidget *button; -+ button = gtk_button_new_with_mnemonic(_("_Browse...")); -+ GTK_WIDGET_UNSET_FLAGS (button, GTK_CAN_FOCUS); -+ g_signal_connect(G_OBJECT(button),"clicked", G_CALLBACK(on_setup_dictionary_export_browse_button_clicked), this); -+ gtk_box_pack_start (GTK_BOX (hbox1), button, FALSE, FALSE, 0); -+ gtk_box_pack_start(GTK_BOX(vbox1), hbox1, FALSE, FALSE, 0); -+} -+ -+void PrefsDlg::on_markup_search_word(GtkToggleButton *button, PrefsDlg *) -+{ -+ conf->set_bool_at("dictionary/markup_search_word", -+ gtk_toggle_button_get_active(button)); -+} -+ -+void PrefsDlg::setup_dict_article_rendering() -+{ -+ GtkWidget *vbox = prepare_page(GTK_NOTEBOOK(notebook), _("Article rendering"), -+ GTK_STOCK_CONVERT); -+ GtkWidget *vbox1 = gtk_vbox_new(FALSE, 6); -+ gtk_box_pack_start(GTK_BOX(vbox), vbox1, FALSE, FALSE, 0); -+ -+ GtkWidget *ck_btn = -+ gtk_check_button_new_with_mnemonic(_("_Highlight search term")); -+ gtk_box_pack_start(GTK_BOX(vbox1), ck_btn, FALSE, FALSE, 0); -+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(ck_btn), -+ conf->get_bool_at("dictionary/markup_search_word")); -+ g_signal_connect(G_OBJECT(ck_btn), "toggled", -+ G_CALLBACK(on_markup_search_word), this); -+} -+ -+void PrefsDlg::on_setup_dictionary_sound_ckbutton_toggled(GtkToggleButton *button, PrefsDlg *oPrefsDlg) -+{ -+ gboolean enable = gtk_toggle_button_get_active(button); -+ conf->set_bool_at("dictionary/enable_sound_event",enable); -+} -+ -+#ifndef _WIN32 -+void PrefsDlg::on_setup_dictionary_use_tts_program_ckbutton_toggled(GtkToggleButton *button, PrefsDlg *oPrefsDlg) -+{ -+ gboolean enable = gtk_toggle_button_get_active(button); -+ gtk_widget_set_sensitive(oPrefsDlg->use_tts_program_hbox,enable); -+ conf->set_bool("/apps/stardict/preferences/dictionary/use_tts_program", enable); -+ gpAppFrame->oReadWord.use_command_tts = enable; -+ gpAppFrame->oMidWin.oToolWin.UpdatePronounceMenu(); -+} -+#endif -+ -+void PrefsDlg::setup_dictionary_sound_page() -+{ -+ GtkWidget *vbox = prepare_page(GTK_NOTEBOOK(notebook), _("Sound"), GTK_STOCK_YES); -+ GtkWidget *vbox1 = gtk_vbox_new(false, 6); -+ gtk_box_pack_start(GTK_BOX(vbox),vbox1,false,false, 0); -+ -+ GtkWidget *check_button; -+ check_button = gtk_check_button_new_with_mnemonic(_("_Enable sound event.")); -+ bool enable= -+ conf->get_bool_at("dictionary/enable_sound_event"); -+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(check_button), enable); -+ g_signal_connect (G_OBJECT (check_button), "toggled", G_CALLBACK (on_setup_dictionary_sound_ckbutton_toggled), (gpointer)this); -+ gtk_box_pack_start(GTK_BOX(vbox1),check_button,false,false,0); -+ GtkWidget *label; -+#if defined(CONFIG_GTK) || defined(CONFIG_GPE) -+ GtkWidget *hbox2 = gtk_hbox_new(FALSE, 6); -+ label=gtk_label_new(_("Command for playing wav files:")); -+ gtk_box_pack_start(GTK_BOX(hbox2), label, FALSE, FALSE, 0); -+ GtkWidget *e = gtk_entry_new(); -+ gtk_widget_set_size_request(e, 50, -1); -+ const std::string &playcmd= -+ conf->get_string_at("dictionary/play_command"); -+ gtk_entry_set_text(GTK_ENTRY(e), playcmd.c_str()); -+ gtk_box_pack_start(GTK_BOX(hbox2), e, TRUE, TRUE, 0); -+ gtk_widget_set_sensitive(hbox2, enable); -+ ePlayCommand=GTK_ENTRY(e); -+ gtk_box_pack_start(GTK_BOX(vbox1), hbox2, FALSE, FALSE, 0); -+#endif -+ -+ label = gtk_label_new(_("RealPeopleTTS search path:")); -+ gtk_misc_set_alignment(GTK_MISC(label), 0, .5); -+ gtk_box_pack_start(GTK_BOX(vbox1),label,false,false,0); -+ tts_textview = gtk_text_view_new(); -+ gtk_widget_set_size_request(tts_textview, -1, 70); -+ gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(tts_textview), GTK_WRAP_CHAR); -+ const std::string &ttspath = conf->get_string_at("dictionary/tts_path"); -+ GtkTextBuffer *text_view_buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(tts_textview)); -+ gtk_text_buffer_set_text(text_view_buffer, ttspath.c_str(), -1); -+ GtkWidget *scrolled_window = gtk_scrolled_window_new(NULL, NULL); -+ gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolled_window), -+ GTK_SHADOW_ETCHED_IN); -+ gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window), -+ GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); -+ gtk_container_add(GTK_CONTAINER(scrolled_window), tts_textview); -+ gtk_box_pack_start(GTK_BOX(vbox1),scrolled_window,false,false,0); -+ -+#ifndef _WIN32 -+ check_button = gtk_check_button_new_with_mnemonic(_("_Use TTS program.")); -+ enable = conf->get_bool("/apps/stardict/preferences/dictionary/use_tts_program"); -+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(check_button), enable); -+ g_signal_connect (G_OBJECT (check_button), "toggled", G_CALLBACK (on_setup_dictionary_use_tts_program_ckbutton_toggled), this); -+ gtk_box_pack_start(GTK_BOX(vbox1),check_button,false,false,0); -+ use_tts_program_hbox = gtk_hbox_new(FALSE, 6); -+ gtk_box_pack_start(GTK_BOX(vbox1),use_tts_program_hbox,false,false,0); -+ gtk_widget_set_sensitive(use_tts_program_hbox,enable); -+ label = gtk_label_new(_("Commandline:")); -+ gtk_misc_set_alignment(GTK_MISC(label), 0, .5); -+ gtk_box_pack_start(GTK_BOX(use_tts_program_hbox),label,false,false,0); -+ GtkWidget *comboboxentry = gtk_combo_box_entry_new_text(); -+ gtk_widget_set_size_request(comboboxentry, 30, -1); -+ gtk_combo_box_append_text(GTK_COMBO_BOX(comboboxentry), "echo %s | festival --tts &"); -+ gtk_combo_box_append_text(GTK_COMBO_BOX(comboboxentry), "espeak %s &"); -+ eTTSCommandline = GTK_ENTRY(GTK_BIN(comboboxentry)->child); -+ const std::string &tts_program_cmdline = conf->get_string("/apps/stardict/preferences/dictionary/tts_program_cmdline"); -+ gtk_entry_set_text(eTTSCommandline, tts_program_cmdline.c_str()); -+ gtk_box_pack_start(GTK_BOX(use_tts_program_hbox),comboboxentry,true,true,0); -+#endif -+} -+ -+void PrefsDlg::on_setup_network_netdict_ckbutton_toggled(GtkToggleButton *button, PrefsDlg *oPrefsDlg) -+{ -+ conf->set_bool_at("network/enable_netdict", -+ gtk_toggle_button_get_active(button)); -+} -+ -+static void on_account_passwd_entry_activated(GtkEntry *entry, GtkDialog *dialog) -+{ -+ gtk_dialog_response(dialog, GTK_RESPONSE_OK); -+} -+ -+void PrefsDlg::on_setup_network_account_button_clicked(GtkWidget *widget, PrefsDlg *oPrefsDlg) -+{ -+ GtkWidget *account_dialog; -+ account_dialog = -+ gtk_dialog_new_with_buttons (_("Account"), -+ GTK_WINDOW (oPrefsDlg->window), -+ GTK_DIALOG_DESTROY_WITH_PARENT, -+ GTK_STOCK_CANCEL, -+ GTK_RESPONSE_CANCEL, -+ GTK_STOCK_OK, -+ GTK_RESPONSE_OK, -+ NULL); -+ GtkWidget *table = gtk_table_new(2, 2, FALSE); -+ gtk_container_add(GTK_CONTAINER(GTK_DIALOG(account_dialog)->vbox), table); -+ gtk_container_set_border_width(GTK_CONTAINER(table), 6); -+ GtkWidget *label = gtk_label_new_with_mnemonic(_("_User Name:")); -+ gtk_misc_set_alignment(GTK_MISC(label), 0, .5); -+ GtkWidget *user_entry = gtk_entry_new (); -+ gtk_label_set_mnemonic_widget(GTK_LABEL(label), user_entry); -+ gtk_table_attach(GTK_TABLE(table), label, 0, 1, 0, 1, GTK_FILL, (GtkAttachOptions)0, 6, 4); -+ gtk_table_attach(GTK_TABLE(table), user_entry, 1, 2, 0, 1, GTK_EXPAND, (GtkAttachOptions)0, 0, 4); -+ label = gtk_label_new_with_mnemonic(_("_Password:")); -+ gtk_misc_set_alignment (GTK_MISC (label), 0, .5); -+ GtkWidget *passwd_entry = gtk_entry_new (); -+ gtk_entry_set_visibility(GTK_ENTRY(passwd_entry), FALSE); -+ g_signal_connect(G_OBJECT(passwd_entry),"activate", G_CALLBACK(on_account_passwd_entry_activated), account_dialog); -+ gtk_label_set_mnemonic_widget (GTK_LABEL (label), passwd_entry); -+ gtk_table_attach(GTK_TABLE(table), label, 0, 1, 1, 2, GTK_FILL, (GtkAttachOptions)0, 6, 4); -+ gtk_table_attach(GTK_TABLE(table), passwd_entry, 1, 2, 1, 2, GTK_EXPAND, (GtkAttachOptions)0, 0, 4); -+ gtk_dialog_set_default_response(GTK_DIALOG(account_dialog), GTK_RESPONSE_OK); -+ gtk_window_set_resizable(GTK_WINDOW(account_dialog), FALSE); -+ gtk_widget_show_all(GTK_WIDGET(account_dialog)); -+ while (gtk_dialog_run(GTK_DIALOG(account_dialog))==GTK_RESPONSE_OK) { -+ const gchar *user = gtk_entry_get_text(GTK_ENTRY(user_entry)); -+ if (!user[0]) { -+ conf->set_string_at("network/user", ""); -+ conf->set_string_at("network/md5passwd", ""); -+ gtk_button_set_label(oPrefsDlg->bAccount, "Guest"); -+ gpAppFrame->oStarDictClient.set_auth("", ""); -+ break; -+ } -+ gchar *error_msg = NULL; -+ const gchar *passwd = gtk_entry_get_text(GTK_ENTRY(passwd_entry)); -+ if (!passwd[0]) -+ error_msg = _("Please input the password."); -+ if (error_msg) { -+ GtkWidget *message_dlg = -+ gtk_message_dialog_new( -+ GTK_WINDOW(account_dialog), -+ (GtkDialogFlags) (GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT), -+ GTK_MESSAGE_INFO, GTK_BUTTONS_OK, -+ error_msg); -+ gtk_dialog_set_default_response(GTK_DIALOG(message_dlg), GTK_RESPONSE_OK); -+ gtk_window_set_resizable(GTK_WINDOW(message_dlg), FALSE); -+ gtk_dialog_run(GTK_DIALOG(message_dlg)); -+ gtk_widget_destroy(message_dlg); -+ continue; -+ } -+ conf->set_string_at("network/user", user); -+ struct MD5Context ctx; -+ unsigned char digest[16]; -+ MD5Init(&ctx); -+ MD5Update(&ctx, (const unsigned char*)passwd, strlen(passwd)); -+ MD5Final(digest, &ctx ); -+ char hex[33]; -+ for (int i = 0; i < 16; i++) -+ sprintf( hex+2*i, "%02x", digest[i] ); -+ hex[32] = '\0'; -+ conf->set_string_at("network/md5passwd", hex); -+ gtk_button_set_label(oPrefsDlg->bAccount, user); -+ gpAppFrame->oStarDictClient.set_auth(user, hex); -+ break; -+ } -+ gtk_widget_destroy(account_dialog); -+} -+ -+void PrefsDlg::on_register_end(const char *msg) -+{ -+ gtk_button_set_label(bAccount, register_user.c_str()); -+ conf->set_string_at("network/user", register_user); -+ conf->set_string_at("network/md5passwd", register_hex); -+ gpAppFrame->oStarDictClient.set_auth(register_user.c_str(), register_hex.c_str()); -+ -+ GtkWidget *message_dlg = gtk_message_dialog_new(GTK_WINDOW(window), -+ (GtkDialogFlags) (GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT), -+ GTK_MESSAGE_INFO, GTK_BUTTONS_OK, msg); -+ gtk_dialog_set_default_response(GTK_DIALOG(message_dlg), GTK_RESPONSE_OK); -+ gtk_window_set_resizable(GTK_WINDOW(message_dlg), FALSE); -+ g_signal_connect_swapped (message_dlg, "response", G_CALLBACK (gtk_widget_destroy), message_dlg); -+ gtk_widget_show(message_dlg); -+} -+ -+static void on_register_email_button_activated(GtkEntry *entry, GtkDialog *dialog) -+{ -+ gtk_dialog_response(dialog, GTK_RESPONSE_OK); -+} -+ -+void PrefsDlg::on_setup_network_register_button_clicked(GtkWidget *widget, PrefsDlg *oPrefsDlg) -+{ -+ GtkWidget *register_dialog; -+ register_dialog = -+ gtk_dialog_new_with_buttons (_("Register"), -+ GTK_WINDOW (oPrefsDlg->window), -+ GTK_DIALOG_DESTROY_WITH_PARENT, -+ GTK_STOCK_CANCEL, -+ GTK_RESPONSE_CANCEL, -+ GTK_STOCK_OK, -+ GTK_RESPONSE_OK, -+ NULL); -+ GtkWidget *table = gtk_table_new(3, 2, FALSE); -+ gtk_container_add(GTK_CONTAINER(GTK_DIALOG(register_dialog)->vbox), table); -+ gtk_container_set_border_width(GTK_CONTAINER(table), 6); -+ GtkWidget *label = gtk_label_new_with_mnemonic(_("_User Name:")); -+ gtk_misc_set_alignment(GTK_MISC(label), 0, .5); -+ GtkWidget *user_entry = gtk_entry_new (); -+ gtk_label_set_mnemonic_widget(GTK_LABEL(label), user_entry); -+ gtk_table_attach(GTK_TABLE(table), label, 0, 1, 0, 1, GTK_FILL, (GtkAttachOptions)0, 6, 4); -+ gtk_table_attach(GTK_TABLE(table), user_entry, 1, 2, 0, 1, GTK_EXPAND, (GtkAttachOptions)0, 0, 4); -+ label = gtk_label_new_with_mnemonic(_("_Password:")); -+ gtk_misc_set_alignment (GTK_MISC (label), 0, .5); -+ GtkWidget *passwd_entry = gtk_entry_new (); -+ gtk_entry_set_visibility(GTK_ENTRY(passwd_entry), FALSE); -+ gtk_label_set_mnemonic_widget (GTK_LABEL (label), passwd_entry); -+ gtk_table_attach(GTK_TABLE(table), label, 0, 1, 1, 2, GTK_FILL, (GtkAttachOptions)0, 6, 4); -+ gtk_table_attach(GTK_TABLE(table), passwd_entry, 1, 2, 1, 2, GTK_EXPAND, (GtkAttachOptions)0, 0, 4); -+ label = gtk_label_new_with_mnemonic(_("_Email:")); -+ gtk_misc_set_alignment(GTK_MISC(label), 0, .5); -+ GtkWidget *email_entry = gtk_entry_new (); -+ g_signal_connect(G_OBJECT(email_entry),"activate", G_CALLBACK(on_register_email_button_activated), register_dialog); -+ gtk_label_set_mnemonic_widget(GTK_LABEL(label), email_entry); -+ gtk_table_attach(GTK_TABLE(table), label, 0, 1, 2, 3, GTK_FILL, (GtkAttachOptions)0, 6, 4); -+ gtk_table_attach(GTK_TABLE(table), email_entry, 1, 2, 2, 3, GTK_EXPAND, (GtkAttachOptions)0, 0, 4); -+ gtk_dialog_set_default_response(GTK_DIALOG(register_dialog), GTK_RESPONSE_OK); -+ gtk_window_set_resizable(GTK_WINDOW(register_dialog), FALSE); -+ gtk_widget_show_all(GTK_WIDGET(register_dialog)); -+ while (gtk_dialog_run(GTK_DIALOG(register_dialog))==GTK_RESPONSE_OK) { -+ gchar *error_msg = NULL; -+ const gchar *user = gtk_entry_get_text(GTK_ENTRY(user_entry)); -+ const gchar *passwd = gtk_entry_get_text(GTK_ENTRY(passwd_entry)); -+ const gchar *email = gtk_entry_get_text(GTK_ENTRY(email_entry)); -+ if (!user[0]) -+ error_msg = _("Please input the user name."); -+ else if (!passwd[0]) -+ error_msg = _("Please input the password."); -+ else if (!email[0]) -+ error_msg = _("Please input the email."); -+ else if (strchr(email, '@')==NULL) -+ error_msg = _("Please input a valid email."); -+ if (error_msg) { -+ GtkWidget *message_dlg = -+ gtk_message_dialog_new( -+ GTK_WINDOW(register_dialog), -+ (GtkDialogFlags) (GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT), -+ GTK_MESSAGE_INFO, GTK_BUTTONS_OK, -+ error_msg); -+ gtk_dialog_set_default_response(GTK_DIALOG(message_dlg), GTK_RESPONSE_OK); -+ gtk_window_set_resizable(GTK_WINDOW(message_dlg), FALSE); -+ gtk_dialog_run(GTK_DIALOG(message_dlg)); -+ gtk_widget_destroy(message_dlg); -+ continue; -+ } -+ struct MD5Context ctx; -+ unsigned char digest[16]; -+ MD5Init(&ctx); -+ MD5Update(&ctx, (const unsigned char*)passwd, strlen(passwd)); -+ MD5Final(digest, &ctx ); -+ char hex[33]; -+ for (int i = 0; i < 16; i++) -+ sprintf( hex+2*i, "%02x", digest[i] ); -+ hex[32] = '\0'; -+ const gchar *server = gtk_entry_get_text(oPrefsDlg->eStarDictServer); -+ int port = atoi(gtk_entry_get_text(oPrefsDlg->eStarDictServerPort)); -+ gpAppFrame->oStarDictClient.set_server(server, port); -+ gpAppFrame->oStarDictClient.set_auth("", ""); -+ oPrefsDlg->register_user = user; -+ oPrefsDlg->register_hex = hex; -+ STARDICT::Cmd *c = new STARDICT::Cmd(STARDICT::CMD_REGISTER, user, hex, email); -+ gpAppFrame->oStarDictClient.send_commands(1, c); -+ break; -+ } -+ gtk_widget_destroy(register_dialog); -+} -+ -+void PrefsDlg::setup_network_netdict() -+{ -+ GtkWidget *vbox = prepare_page(GTK_NOTEBOOK(notebook), _("Net Dict"), -+ GTK_STOCK_NETWORK); -+ GtkWidget *vbox1 = gtk_vbox_new(FALSE, 6); -+ gtk_box_pack_start(GTK_BOX(vbox), vbox1, FALSE, FALSE, 0); -+ -+ GtkWidget *ck_btn = -+ gtk_check_button_new_with_mnemonic(_("Enable _network dictionaries.")); -+ gtk_box_pack_start(GTK_BOX(vbox1), ck_btn, FALSE, FALSE, 0); -+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(ck_btn), -+ conf->get_bool_at("network/enable_netdict")); -+ g_signal_connect(G_OBJECT(ck_btn), "toggled", -+ G_CALLBACK(on_setup_network_netdict_ckbutton_toggled), this); -+ -+ GtkWidget *table; -+ table = gtk_table_new(3, 2, FALSE); -+ gtk_table_set_row_spacings(GTK_TABLE(table), 6); -+ gtk_table_set_col_spacings(GTK_TABLE(table), 6); -+ gtk_box_pack_start(GTK_BOX(vbox1),table,false,false,0); -+ GtkWidget *label=gtk_label_new(_("StarDict server:")); -+ gtk_table_attach(GTK_TABLE(table), label, 0, 1, 0, 1, GTK_FILL, GTK_FILL, 0, 0); -+ GtkWidget *comboboxentry = gtk_combo_box_entry_new_text(); -+ gtk_table_attach(GTK_TABLE(table), comboboxentry, 1, 2, 0, 1, GTK_FILL, GTK_FILL, 0, 0); -+ gtk_combo_box_append_text(GTK_COMBO_BOX(comboboxentry), "dict.stardict.org"); -+ gtk_combo_box_append_text(GTK_COMBO_BOX(comboboxentry), "dict.stardict.cn"); -+ eStarDictServer=GTK_ENTRY(GTK_BIN(comboboxentry)->child); -+ const std::string &server= conf->get_string_at("network/server"); -+ gtk_entry_set_text(eStarDictServer, server.c_str()); -+ label=gtk_label_new(_("Port:")); -+ gtk_table_attach(GTK_TABLE(table), label, 0, 1, 1, 2, GTK_FILL, GTK_FILL, 0, 0); -+ GtkWidget *e = gtk_entry_new(); -+ int port = conf->get_int_at("network/port"); -+ gchar *str = g_strdup_printf("%d", port); -+ gtk_entry_set_text(GTK_ENTRY(e), str); -+ g_free(str); -+ gtk_table_attach(GTK_TABLE(table), e, 1, 2, 1, 2, GTK_FILL, GTK_FILL, 0, 0); -+ eStarDictServerPort=GTK_ENTRY(e); -+ label=gtk_label_new(_("Account:")); -+ gtk_table_attach(GTK_TABLE(table), label, 0, 1, 2, 3, GTK_FILL, GTK_FILL, 0, 0); -+ const std::string &user= conf->get_string_at("network/user"); -+ GtkWidget *button; -+ if (user.empty()) -+ button = gtk_button_new_with_label("Guest"); -+ else -+ button = gtk_button_new_with_label(user.c_str()); -+ g_signal_connect(G_OBJECT(button),"clicked", G_CALLBACK(on_setup_network_account_button_clicked), this); -+ gtk_table_attach(GTK_TABLE(table), button, 1, 2, 2, 3, GTK_FILL, GTK_FILL, 0, 0); -+ bAccount = GTK_BUTTON(button); -+ button = gtk_button_new_with_mnemonic(_("_Register an account")); -+ g_signal_connect(G_OBJECT(button),"clicked", G_CALLBACK(on_setup_network_register_button_clicked), this); -+ GtkWidget *hbox1 = gtk_hbox_new(FALSE, 6); -+ gtk_box_pack_start(GTK_BOX(hbox1),button,false,false,0); -+ gtk_box_pack_start(GTK_BOX(vbox1),hbox1,false,false,0); -+} -+ -+void PrefsDlg::on_setup_mainwin_searchWhileTyping_ckbutton_toggled(GtkToggleButton *button, PrefsDlg *oPrefsDlg) -+{ -+ conf->set_bool_at("main_window/search_while_typing", -+ gtk_toggle_button_get_active(button)); -+} -+ -+void PrefsDlg::on_setup_mainwin_showfirstWhenNotfound_ckbutton_toggled(GtkToggleButton *button, PrefsDlg *oPrefsDlg) -+{ -+ conf->set_bool_at("main_window/showfirst_when_notfound", -+ gtk_toggle_button_get_active(button)); -+} -+ -+void PrefsDlg::on_setup_mainwin_input_timeout_spinbutton_changed(GtkSpinButton *button, PrefsDlg *oPrefsDlg) -+{ -+ gint timeout = gtk_spin_button_get_value_as_int(button); -+ conf->set_int_at("main_window/word_change_timeout", timeout); -+ gpAppFrame->word_change_timeout = timeout; -+} -+ -+void PrefsDlg::setup_mainwin_input_page() -+{ -+ GtkWidget *vbox = prepare_page(GTK_NOTEBOOK(notebook), _("Input"), -+ GTK_STOCK_EDIT); -+ -+ GtkWidget *vbox1 = gtk_vbox_new(FALSE, 6); -+ gtk_box_pack_start(GTK_BOX(vbox),vbox1,FALSE,FALSE, 0); -+ -+ GtkWidget *check_button = -+ gtk_check_button_new_with_mnemonic(_("_Search while typing.")); -+ gtk_box_pack_start(GTK_BOX(vbox1), check_button, FALSE, FALSE, 0); -+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(check_button), -+ conf->get_bool_at("main_window/search_while_typing")); -+ g_signal_connect(G_OBJECT(check_button), "toggled", -+ G_CALLBACK(on_setup_mainwin_searchWhileTyping_ckbutton_toggled), this); -+ GtkWidget *hbox = gtk_hbox_new(false, 5); -+ gtk_box_pack_start(GTK_BOX(vbox1),hbox,FALSE,FALSE, 0); -+ GtkWidget *label=gtk_label_new(NULL); -+ gtk_label_set_markup_with_mnemonic(GTK_LABEL(label), _("Word change _timeout:")); -+ gtk_box_pack_start(GTK_BOX(hbox),label,FALSE,FALSE, 0); -+ GtkWidget *spin_button; -+ spin_button = gtk_spin_button_new_with_range(50,2000,50); -+ gtk_label_set_mnemonic_widget(GTK_LABEL(label), spin_button); -+ gtk_spin_button_set_update_policy(GTK_SPIN_BUTTON(spin_button), GTK_UPDATE_IF_VALID); -+ gtk_spin_button_set_value(GTK_SPIN_BUTTON(spin_button), conf->get_int_at("main_window/word_change_timeout")); -+ g_signal_connect(G_OBJECT(spin_button), "value-changed", G_CALLBACK(on_setup_mainwin_input_timeout_spinbutton_changed), this); -+ gtk_box_pack_start(GTK_BOX(hbox),spin_button,FALSE,FALSE, 0); -+ label=gtk_label_new(_("(default:300)")); -+ gtk_box_pack_start(GTK_BOX(hbox),label,FALSE,FALSE, 0); -+ check_button = gtk_check_button_new_with_mnemonic(_("Show the _first word when not found.")); -+ gtk_box_pack_start(GTK_BOX(vbox1),check_button,FALSE,FALSE,0); -+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(check_button), conf->get_bool_at("main_window/showfirst_when_notfound")); -+ g_signal_connect(G_OBJECT(check_button), "toggled", -+ G_CALLBACK(on_setup_mainwin_showfirstWhenNotfound_ckbutton_toggled), this); -+} -+ -+void PrefsDlg::on_setup_mainwin_startup_ckbutton_toggled(GtkToggleButton *button, PrefsDlg *oPrefsDlg) -+{ -+ conf->set_bool_at("main_window/hide_on_startup", -+ gtk_toggle_button_get_active(button)); -+} -+ -+#ifdef _WIN32 -+void PrefsDlg::on_setup_mainwin_autorun_ckbutton_toggled(GtkToggleButton *button, PrefsDlg *oPrefsDlg) -+{ -+ gboolean b = gtk_toggle_button_get_active(button); -+ HKEY hKEY; -+ LONG lRet; -+ if (b) { -+ lRet =RegOpenKeyEx(HKEY_CURRENT_USER,"Software\\Microsoft\\Windows\\CurrentVersion\\Run",0,KEY_ALL_ACCESS,&hKEY); -+ if(lRet==ERROR_SUCCESS) { -+ std::string path = gStarDictDataDir+ G_DIR_SEPARATOR_S "stardict.exe"; -+ RegSetValueEx(hKEY, "StarDict", 0, REG_SZ, (const BYTE*)path.c_str(), path.length()+1); -+ RegCloseKey(hKEY); -+ } -+ } else { -+ lRet =RegOpenKeyEx(HKEY_CURRENT_USER,"Software\\Microsoft\\Windows\\CurrentVersion\\Run",0,KEY_ALL_ACCESS,&hKEY); -+ if(lRet==ERROR_SUCCESS) { -+ RegDeleteValue(hKEY, "StarDict"); -+ RegCloseKey(hKEY); -+ } -+ } -+} -+ -+void PrefsDlg::on_setup_mainwin_use_mainwindow_hotkey_ckbutton_toggled(GtkToggleButton *button, PrefsDlg *oPrefsDlg) -+{ -+ gboolean b = gtk_toggle_button_get_active(button); -+ if (b) -+ gpAppFrame->oHotkey.start_mainwindow(); -+ else -+ gpAppFrame->oHotkey.stop_mainwindow(); -+ conf->set_bool_at("dictionary/use_mainwindow_hotkey", b); -+} -+#endif -+ -+void PrefsDlg::on_setup_mainwin_transparent_scale_changed(GtkRange *range, PrefsDlg *oPrefsDlg) -+{ -+ gint transparent = (gint)gtk_range_get_value(range); -+ conf->set_int_at("main_window/transparent", transparent); -+ gtk_window_set_opacity(GTK_WINDOW(gpAppFrame->window), (100-transparent)/100.0); -+} -+ -+void PrefsDlg::setup_mainwin_options_page() -+{ -+ GtkWidget *vbox = prepare_page(GTK_NOTEBOOK(notebook), _("Options"), GTK_STOCK_EXECUTE); -+ GtkWidget *vbox1 = gtk_vbox_new(FALSE, 6); -+ gtk_box_pack_start(GTK_BOX(vbox),vbox1,FALSE,FALSE, 0); -+ -+ GtkWidget *check_button; -+#ifdef _WIN32 -+ check_button = gtk_check_button_new_with_mnemonic(_("_Auto run StarDict after boot.")); -+ gtk_box_pack_start(GTK_BOX(vbox1),check_button,FALSE,FALSE,0); -+ gboolean autorun; -+ -+ HKEY hKEY; -+ LONG lRet =RegOpenKeyEx(HKEY_CURRENT_USER,"Software\\Microsoft\\Windows\\CurrentVersion\\Run",0,KEY_QUERY_VALUE,&hKEY); -+ if(lRet!=ERROR_SUCCESS) { -+ autorun = false; -+ } else { -+ char owner_Get[80]; -+ DWORD cbData_1=80; -+ DWORD type_1=REG_SZ; -+ lRet=RegQueryValueEx(hKEY,"StarDict",NULL,&type_1,(LPBYTE)owner_Get,&cbData_1); -+ RegCloseKey(hKEY); -+ if((lRet!=ERROR_SUCCESS)||(cbData_1 > 80)) { -+ autorun = false; -+ } else { -+ std::string path = gStarDictDataDir+ G_DIR_SEPARATOR_S "stardict.exe"; -+ if (strcmp(path.c_str(), owner_Get)==0) -+ autorun = true; -+ else -+ autorun = false; -+ } -+ } -+ -+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(check_button), autorun); -+ g_signal_connect(G_OBJECT(check_button), "toggled", -+ G_CALLBACK(on_setup_mainwin_autorun_ckbutton_toggled), this); -+#endif -+ -+ check_button = gtk_check_button_new_with_mnemonic(_("Hide main window when _starting StarDict.")); -+ gtk_box_pack_start(GTK_BOX(vbox1), check_button, FALSE, FALSE, 0); -+ bool hide= -+ conf->get_bool_at("main_window/hide_on_startup"); -+ -+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(check_button), hide); -+ g_signal_connect(G_OBJECT(check_button), "toggled", -+ G_CALLBACK(on_setup_mainwin_startup_ckbutton_toggled), this); -+ -+#ifdef _WIN32 -+ check_button = gtk_check_button_new_with_mnemonic(_("_Use open main window hotkey: Ctrl+Alt+Z.")); -+ gtk_box_pack_start(GTK_BOX(vbox1),check_button,false,false,0); -+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(check_button), conf->get_bool_at("dictionary/use_mainwindow_hotkey")); -+ g_signal_connect(G_OBJECT(check_button), "toggled", -+ G_CALLBACK(on_setup_mainwin_use_mainwindow_hotkey_ckbutton_toggled), this); -+#endif -+ -+ GtkWidget *hbox = gtk_hbox_new(false, 5); -+ gtk_box_pack_start(GTK_BOX(vbox1),hbox,FALSE,FALSE, 0); -+ GtkWidget *label=gtk_label_new(NULL); -+ gtk_label_set_markup_with_mnemonic(GTK_LABEL(label), _("_Transparency:")); -+ gtk_box_pack_start(GTK_BOX(hbox),label,FALSE,FALSE, 0); -+ GtkWidget *hscale; -+ hscale = gtk_hscale_new_with_range(0,80,1); -+ gtk_label_set_mnemonic_widget(GTK_LABEL(label), hscale); -+ int transparent=conf->get_int_at("main_window/transparent"); -+ gtk_range_set_value(GTK_RANGE(hscale), transparent); -+ g_signal_connect(G_OBJECT(hscale), "value-changed", G_CALLBACK(on_setup_mainwin_transparent_scale_changed), this); -+ gtk_box_pack_start(GTK_BOX(hbox),hscale,TRUE,TRUE, 0); -+} -+ -+void PrefsDlg::write_mainwin_searchwebsite_list() -+{ -+ GtkTreeIter iter; -+ gboolean have_iter; -+ gchar *website_name, *website_link, *website_searchlink; -+ std::list<std::string> searchwebsite_list; -+ GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW (searchwebsite_treeview)); -+ -+ have_iter = gtk_tree_model_get_iter_first(model, &iter); -+ while (have_iter) { -+ gtk_tree_model_get (model, &iter, 0, &website_name, 1, &website_link, 2, &website_searchlink, -1); -+ std::string website(std::string(website_name)+'\t'+website_link+'\t'+website_searchlink); -+ g_free(website_name); -+ g_free(website_link); -+ g_free(website_searchlink); -+ searchwebsite_list.push_back(website); -+ have_iter = gtk_tree_model_iter_next(model, &iter); -+ } -+ conf->set_strlist_at("main_window/search_website_list", searchwebsite_list); -+} -+ -+void PrefsDlg::on_setup_mainwin_searchwebsite_moveup_button_clicked(GtkWidget *widget, PrefsDlg *oPrefsDlg) -+{ -+ GtkTreeSelection *selection; -+ selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (oPrefsDlg->searchwebsite_treeview)); -+ GtkTreeModel *model; -+ GtkTreeIter iter; -+ if (gtk_tree_selection_get_selected(selection, &model, &iter)) { -+ GtkTreePath* path = gtk_tree_model_get_path(model, &iter); -+ if (gtk_tree_path_prev(path)) { -+ GtkTreeIter prev; -+ gtk_tree_model_get_iter(model, &prev, path); -+ gtk_list_store_swap(GTK_LIST_STORE(model), &iter, &prev); -+ gtk_tree_selection_select_path(selection, path); -+ gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW (oPrefsDlg->searchwebsite_treeview), path, NULL, false, 0, 0); -+ oPrefsDlg->write_mainwin_searchwebsite_list(); -+ } -+ gtk_tree_path_free(path); -+ } -+} -+ -+void PrefsDlg::on_setup_mainwin_searchwebsite_movedown_button_clicked(GtkWidget *widget, PrefsDlg *oPrefsDlg) -+{ -+ GtkTreeSelection *selection; -+ selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (oPrefsDlg->searchwebsite_treeview)); -+ GtkTreeModel *model; -+ GtkTreeIter iter; -+ if (gtk_tree_selection_get_selected(selection, &model, &iter)) { -+ GtkTreePath* path = gtk_tree_model_get_path(model, &iter); -+ gtk_tree_path_next(path); -+ GtkTreeIter next; -+ if (gtk_tree_model_get_iter(model, &next, path)) { -+ gtk_list_store_swap(GTK_LIST_STORE(model), &iter, &next); -+ gtk_tree_selection_select_path(selection, path); -+ gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW (oPrefsDlg->searchwebsite_treeview), path, NULL, false, 0, 0); -+ oPrefsDlg->write_mainwin_searchwebsite_list(); -+ } -+ gtk_tree_path_free(path); -+ } -+} -+ -+void PrefsDlg::on_setup_mainwin_searchwebsite_add_button_clicked(GtkWidget *widget, PrefsDlg *oPrefsDlg) -+{ -+ GtkWidget *searchwebsite_add_dialog; -+ GtkWidget *searchwebsite_add_dialog_name_entry; -+ GtkWidget *searchwebsite_add_dialog_link_entry; -+ GtkWidget *searchwebsite_add_dialog_searchlink_entry; -+ -+ searchwebsite_add_dialog = -+ gtk_dialog_new_with_buttons (_("Add"), -+ GTK_WINDOW (oPrefsDlg->window), -+ GTK_DIALOG_DESTROY_WITH_PARENT, -+ GTK_STOCK_CANCEL, -+ GTK_RESPONSE_CANCEL, -+ GTK_STOCK_OK, -+ GTK_RESPONSE_OK, -+ NULL); -+ GtkWidget *table = gtk_table_new(3, 2, FALSE); -+ gtk_container_add(GTK_CONTAINER(GTK_DIALOG(searchwebsite_add_dialog)->vbox), table); -+#ifndef CONFIG_GPE -+ gtk_container_set_border_width(GTK_CONTAINER(table), 6); -+#endif -+ GtkWidget *label = gtk_label_new_with_mnemonic(_("Website Name")); -+ gtk_misc_set_alignment(GTK_MISC(label), 0, .5); -+ searchwebsite_add_dialog_name_entry = gtk_entry_new (); -+#ifdef CONFIG_GPE -+ gtk_widget_set_size_request(searchwebsite_add_dialog_name_entry, 100, -1); -+#endif -+ gtk_entry_set_activates_default(GTK_ENTRY(searchwebsite_add_dialog_name_entry), TRUE); -+ gtk_label_set_mnemonic_widget(GTK_LABEL(label), searchwebsite_add_dialog_name_entry); -+ gtk_table_attach(GTK_TABLE(table), label, 0, 1, 0, 1, GTK_FILL, (GtkAttachOptions)0, 6, 4); -+ gtk_table_attach(GTK_TABLE(table), searchwebsite_add_dialog_name_entry, 1, 2, 0, 1, GTK_EXPAND, (GtkAttachOptions)0, 0, 4); -+ -+ -+ label = gtk_label_new_with_mnemonic(_("Website link")); -+ gtk_misc_set_alignment (GTK_MISC (label), 0, .5); -+ searchwebsite_add_dialog_link_entry = gtk_entry_new (); -+#ifdef CONFIG_GPE -+ gtk_widget_set_size_request(searchwebsite_add_dialog_link_entry, 100, -1); -+#endif -+ gtk_entry_set_activates_default (GTK_ENTRY (searchwebsite_add_dialog_link_entry), TRUE); -+ gtk_label_set_mnemonic_widget (GTK_LABEL (label), searchwebsite_add_dialog_link_entry); -+ gtk_table_attach(GTK_TABLE(table), label, 0, 1, 1, 2, GTK_FILL, (GtkAttachOptions)0, 6, 4); -+ gtk_table_attach(GTK_TABLE(table), searchwebsite_add_dialog_link_entry, 1, 2, 1, 2, GTK_EXPAND, (GtkAttachOptions)0, 0, 4); -+ -+ label = gtk_label_new_with_mnemonic(_("Website search link")); -+ gtk_misc_set_alignment (GTK_MISC (label), 0, .5); -+ searchwebsite_add_dialog_searchlink_entry = gtk_entry_new (); -+#ifdef CONFIG_GPE -+ gtk_widget_set_size_request(searchwebsite_add_dialog_searchlink_entry, 100, -1); -+#endif -+ gtk_entry_set_activates_default (GTK_ENTRY (searchwebsite_add_dialog_searchlink_entry), TRUE); -+ gtk_label_set_mnemonic_widget (GTK_LABEL (label), searchwebsite_add_dialog_searchlink_entry); -+ gtk_table_attach(GTK_TABLE(table), label, 0, 1, 2, 3, GTK_FILL, (GtkAttachOptions)0, 6, 4); -+ gtk_table_attach(GTK_TABLE(table), searchwebsite_add_dialog_searchlink_entry, 1, 2, 2, 3, GTK_EXPAND, (GtkAttachOptions)0, 0, 4); -+ -+ gtk_dialog_set_default_response(GTK_DIALOG(searchwebsite_add_dialog), GTK_RESPONSE_OK); -+ gtk_window_set_resizable(GTK_WINDOW(searchwebsite_add_dialog), FALSE); -+ -+ gtk_widget_show_all(GTK_WIDGET(searchwebsite_add_dialog)); -+ while (gtk_dialog_run(GTK_DIALOG(searchwebsite_add_dialog))==GTK_RESPONSE_OK) { -+ gchar *error_msg = NULL; -+ const gchar *website_name = gtk_entry_get_text(GTK_ENTRY(searchwebsite_add_dialog_name_entry)); -+ const gchar *website_link = gtk_entry_get_text(GTK_ENTRY(searchwebsite_add_dialog_link_entry)); -+ const gchar *website_searchlink = gtk_entry_get_text(GTK_ENTRY(searchwebsite_add_dialog_searchlink_entry)); -+ if (!website_name[0]) -+ error_msg = _("Please input the website name."); -+ else if (!website_link[0]) -+ error_msg = _("Please input the website link."); -+ else if (!website_searchlink[0]) -+ error_msg = _("Please input the website search link."); -+ else if (!strstr(website_searchlink, "%s")) { -+ error_msg = _("The website search link should contain a \"%%s\" string for querying a word."); -+ } -+ -+ if (error_msg) { -+ GtkWidget *message_dlg = -+ gtk_message_dialog_new( -+ GTK_WINDOW(searchwebsite_add_dialog), -+ (GtkDialogFlags) (GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT), -+ GTK_MESSAGE_INFO, GTK_BUTTONS_OK, -+ error_msg); -+ -+ gtk_dialog_set_default_response(GTK_DIALOG(message_dlg), GTK_RESPONSE_OK); -+ gtk_window_set_resizable(GTK_WINDOW(message_dlg), FALSE); -+ -+ gtk_dialog_run(GTK_DIALOG(message_dlg)); -+ gtk_widget_destroy(message_dlg); -+ continue; -+ } -+ GtkListStore *model = -+ GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(oPrefsDlg->searchwebsite_treeview))); -+ GtkTreeIter iter; -+ gtk_list_store_prepend(model, &iter); -+ gtk_list_store_set(model, &iter, -+ 0, website_name, -+ 1, website_link, -+ 2, website_searchlink, -+ 3, TRUE, -+ -1); -+ oPrefsDlg->write_mainwin_searchwebsite_list(); -+ break; -+ } -+ gtk_widget_destroy(searchwebsite_add_dialog); -+} -+ -+void PrefsDlg::on_setup_mainwin_searchwebsite_remove_button_clicked(GtkWidget *widget, PrefsDlg *oPrefsDlg) -+{ -+ GtkTreeSelection *selection; -+ selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (oPrefsDlg->searchwebsite_treeview)); -+ GtkTreeModel *model; -+ GtkTreeIter iter; -+ if (gtk_tree_selection_get_selected(selection, &model, &iter)) { -+ if (gtk_list_store_remove(GTK_LIST_STORE(model), &iter)) { -+ GtkTreePath* path = gtk_tree_model_get_path(model, &iter); -+ gtk_tree_selection_select_path(selection, path); -+ gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW (oPrefsDlg->searchwebsite_treeview), path, NULL, false, 0, 0); -+ gtk_tree_path_free(path); -+ } -+ oPrefsDlg->write_mainwin_searchwebsite_list(); -+ } -+} -+ -+void PrefsDlg::on_setup_mainwin_searchwebsite_cell_edited(GtkCellRendererText *cell, const gchar *path_string, const gchar *new_text, PrefsDlg *oPrefsDlg) -+{ -+ GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW (oPrefsDlg->searchwebsite_treeview)); -+ GtkTreePath *path = gtk_tree_path_new_from_string (path_string); -+ GtkTreeIter iter; -+ -+ glong column; -+ column = (glong)(g_object_get_data (G_OBJECT (cell), "column")); -+ gtk_tree_model_get_iter (model, &iter, path); -+ -+ switch (column) { -+ case 0: -+ case 1: -+ if (new_text[0]) { -+ gtk_list_store_set (GTK_LIST_STORE (model), &iter, column, new_text, -1); -+ oPrefsDlg->write_mainwin_searchwebsite_list(); -+ } -+ break; -+ case 2: -+ if (new_text[0]) { -+ if (!strstr(new_text, "%s")) { -+ GtkWidget *message_dlg; -+ -+ message_dlg = gtk_message_dialog_new ( -+ GTK_WINDOW (oPrefsDlg->window), -+ (GtkDialogFlags) (GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT), -+ GTK_MESSAGE_INFO, -+ GTK_BUTTONS_OK, -+ _("The website search link should contain a \"%%s\" string for querying a word.")); -+ -+ gtk_dialog_set_default_response (GTK_DIALOG (message_dlg), GTK_RESPONSE_OK); -+ -+ gtk_window_set_resizable (GTK_WINDOW (message_dlg), FALSE); -+ -+ gtk_dialog_run (GTK_DIALOG (message_dlg)); -+ gtk_widget_destroy (message_dlg); -+ } -+ else { -+ gtk_list_store_set (GTK_LIST_STORE (model), &iter, 2, new_text, -1); -+ oPrefsDlg->write_mainwin_searchwebsite_list(); -+ } -+ } -+ break; -+ -+ } -+ -+ gtk_tree_path_free (path); -+} -+ -+void PrefsDlg::setup_mainwin_searchwebsite_page() -+{ -+ GtkWidget *vbox = prepare_page(GTK_NOTEBOOK(notebook), _("Search website"), GTK_STOCK_JUMP_TO); -+ GtkWidget *vbox2; -+ vbox2 = gtk_vbox_new(false, 6); -+ gtk_box_pack_start(GTK_BOX(vbox), vbox2, true, true,0); -+ -+ GtkListStore *model; -+ model = gtk_list_store_new (4, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_BOOLEAN); -+ -+ const std::list<std::string> &web_list= -+ conf->get_strlist_at("main_window/search_website_list"); -+ -+ GtkTreeIter iter; -+ for (std::list<std::string>::const_iterator wit=web_list.begin(); -+ wit!=web_list.end(); ++wit) { -+ std::vector<std::string> l=split(*wit, '\t'); -+ if (l.size()==3) { -+ gtk_list_store_append(model, &iter); -+ gtk_list_store_set(model, &iter, -+ 0, l[0].c_str(), -+ 1, l[1].c_str(), -+ 2, l[2].c_str(), -+ 3, TRUE, -+ -1); -+ } -+ } -+ -+ GtkWidget *sw; -+ sw = gtk_scrolled_window_new (NULL, NULL); -+ gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (sw), GTK_SHADOW_IN); -+ gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw), -+ GTK_POLICY_AUTOMATIC, -+ GTK_POLICY_AUTOMATIC); -+ -+ gtk_widget_set_size_request (sw, 300, 180); -+ -+ searchwebsite_treeview = gtk_tree_view_new_with_model (GTK_TREE_MODEL(model)); -+ g_object_unref (G_OBJECT (model)); -+ gtk_tree_view_set_rules_hint (GTK_TREE_VIEW (searchwebsite_treeview), TRUE); -+ -+ GtkTreeSelection *selection; -+ selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (searchwebsite_treeview)); -+ -+ gtk_tree_selection_set_mode (selection, GTK_SELECTION_SINGLE); -+ -+ GtkCellRenderer *renderer; -+ GtkTreeViewColumn *column; -+ -+ renderer = gtk_cell_renderer_text_new (); -+ g_signal_connect (renderer, "edited", G_CALLBACK (on_setup_mainwin_searchwebsite_cell_edited), this); -+ g_object_set (G_OBJECT (renderer), "xalign", 0.0, NULL); -+ g_object_set_data (G_OBJECT (renderer), "column", GINT_TO_POINTER(0)); -+ column = gtk_tree_view_column_new_with_attributes (_("Website Name"), renderer, "text", 0, "editable", 3, NULL); -+ gtk_tree_view_append_column (GTK_TREE_VIEW(searchwebsite_treeview), column); -+ gtk_tree_view_column_set_clickable (GTK_TREE_VIEW_COLUMN (column), FALSE); -+ -+ renderer = gtk_cell_renderer_text_new (); -+ g_signal_connect (renderer, "edited", G_CALLBACK (on_setup_mainwin_searchwebsite_cell_edited), this); -+ g_object_set (G_OBJECT (renderer), "xalign", 0.0, NULL); -+ g_object_set_data (G_OBJECT (renderer), "column", GINT_TO_POINTER(1)); -+ column = gtk_tree_view_column_new_with_attributes (_("Website link"), renderer, "text", 1, "editable", 3, NULL); -+ gtk_tree_view_append_column (GTK_TREE_VIEW(searchwebsite_treeview), column); -+ gtk_tree_view_column_set_clickable (GTK_TREE_VIEW_COLUMN (column), FALSE); -+ -+ renderer = gtk_cell_renderer_text_new (); -+ g_signal_connect (renderer, "edited", G_CALLBACK (on_setup_mainwin_searchwebsite_cell_edited), this); -+ g_object_set (G_OBJECT (renderer), "xalign", 0.0, NULL); -+ g_object_set_data (G_OBJECT (renderer), "column", GINT_TO_POINTER(2)); -+ column = gtk_tree_view_column_new_with_attributes (_("Website search link"), renderer, "text", 2, "editable", 3, NULL); -+ gtk_tree_view_append_column (GTK_TREE_VIEW(searchwebsite_treeview), column); -+ gtk_tree_view_column_set_clickable (GTK_TREE_VIEW_COLUMN (column), FALSE); -+ -+ gtk_container_add (GTK_CONTAINER (sw), searchwebsite_treeview); -+ gtk_box_pack_start (GTK_BOX (vbox2), sw, TRUE, TRUE, 0); -+ -+ GtkWidget *hbox1; -+ hbox1 = gtk_hbox_new(false,6); -+ GtkWidget *button; -+ button = gtk_button_new(); -+ GtkWidget *image = gtk_image_new_from_stock(GTK_STOCK_GO_UP, GTK_ICON_SIZE_BUTTON); -+ gtk_container_add(GTK_CONTAINER(button), image); -+ GTK_WIDGET_UNSET_FLAGS (button, GTK_CAN_FOCUS); -+ g_signal_connect(G_OBJECT(button),"clicked", G_CALLBACK(on_setup_mainwin_searchwebsite_moveup_button_clicked), this); -+ gtk_box_pack_start (GTK_BOX (hbox1), button, FALSE, FALSE, 0); -+ button = gtk_button_new(); -+ image = gtk_image_new_from_stock(GTK_STOCK_GO_DOWN, GTK_ICON_SIZE_BUTTON); -+ gtk_container_add(GTK_CONTAINER(button), image); -+ GTK_WIDGET_UNSET_FLAGS (button, GTK_CAN_FOCUS); -+ g_signal_connect(G_OBJECT(button),"clicked", G_CALLBACK(on_setup_mainwin_searchwebsite_movedown_button_clicked), this); -+ gtk_box_pack_start (GTK_BOX (hbox1), button, FALSE, FALSE, 0); -+ button = gtk_button_new_from_stock(GTK_STOCK_REMOVE); -+ GTK_WIDGET_UNSET_FLAGS (button, GTK_CAN_FOCUS); -+ g_signal_connect(G_OBJECT(button),"clicked", G_CALLBACK(on_setup_mainwin_searchwebsite_remove_button_clicked), this); -+ gtk_box_pack_end (GTK_BOX (hbox1), button, FALSE, FALSE, 0); -+ -+/* button = gtk_button_new(); -+ GtkWidget *align = gtk_alignment_new (0.5, 0.5, 0.0, 0.0); -+ gtk_container_add (GTK_CONTAINER (button), align); -+ GtkWidget *hbox2 = gtk_hbox_new (FALSE, 2); -+ gtk_container_add (GTK_CONTAINER (align), hbox2); -+ label = gtk_label_new(NULL); -+ gtk_label_set_markup_with_mnemonic(GTK_LABEL(label), _("_Modify")); -+ gtk_label_set_mnemonic_widget(GTK_LABEL(label), button); -+ image = gtk_image_new_from_stock (GTK_STOCK_CONVERT, GTK_ICON_SIZE_BUTTON); -+ gtk_box_pack_start (GTK_BOX (hbox2), image, FALSE, FALSE, 0); -+ gtk_box_pack_end (GTK_BOX (hbox2), label, FALSE, FALSE, 0); -+ GTK_WIDGET_UNSET_FLAGS (button, GTK_CAN_FOCUS); -+ g_signal_connect(G_OBJECT(button),"clicked", G_CALLBACK(on_setup_mainwin_searchwebsite_edit_button_clicked), this); -+ gtk_box_pack_end (GTK_BOX (hbox1), button, FALSE, FALSE, 0);*/ -+ -+ button = gtk_button_new_from_stock(GTK_STOCK_ADD); -+ GTK_WIDGET_UNSET_FLAGS (button, GTK_CAN_FOCUS); -+ g_signal_connect(G_OBJECT(button),"clicked", G_CALLBACK(on_setup_mainwin_searchwebsite_add_button_clicked), this); -+ gtk_box_pack_end (GTK_BOX (hbox1), button, FALSE, FALSE, 0); -+ -+ gtk_box_pack_start (GTK_BOX (vbox2), hbox1, false, false, 0); -+} -+ -+void PrefsDlg::on_setup_NotificationAreaIcon_QueryInFloatWin_ckbutton_toggled(GtkToggleButton *button, PrefsDlg *oPrefsDlg) -+{ -+ gboolean queryin = gtk_toggle_button_get_active(button); -+ conf->set_bool_at("notification_area_icon/query_in_floatwin", -+ queryin); -+} -+ -+void PrefsDlg::setup_NotificationAreaIcon_options_page() -+{ -+ GtkWidget *vbox = prepare_page(GTK_NOTEBOOK(notebook), _("Options"), GTK_STOCK_DND); -+ GtkWidget *hbox1; -+ hbox1 = gtk_hbox_new(false,0); -+ gtk_box_pack_start(GTK_BOX(vbox),hbox1,false,false,0); -+ -+ GtkWidget *check_button; -+ check_button = gtk_check_button_new_with_mnemonic(_("_Query in the floating window when middle mouse\nbutton is clicked.")); -+ bool query_in_floatwin= -+ conf->get_bool_at("notification_area_icon/query_in_floatwin"); -+ -+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(check_button), -+ query_in_floatwin); -+ g_signal_connect(G_OBJECT(check_button), "toggled", -+ G_CALLBACK(on_setup_NotificationAreaIcon_QueryInFloatWin_ckbutton_toggled), this); -+ gtk_box_pack_start(GTK_BOX(hbox1),check_button,false,false,0); -+} -+ -+void PrefsDlg::on_setup_floatwin_pronounce_ckbutton_toggled(GtkToggleButton *button, PrefsDlg *oPrefsDlg) -+{ -+ conf->set_bool_at("floating_window/pronounce_when_popup", -+ gtk_toggle_button_get_active(button)); -+} -+ -+void PrefsDlg::on_setup_show_float_if_not_found(GtkToggleButton *button, PrefsDlg *oPrefsDlg) -+{ -+ conf->set_bool_at("floating_window/show_if_not_found", -+ gtk_toggle_button_get_active(button)); -+} -+ -+void PrefsDlg::setup_floatwin_options_page() -+{ -+ GtkWidget *vbox = prepare_page(GTK_NOTEBOOK(notebook), _("Options"), GTK_STOCK_DND); -+ GtkWidget *vbox1 = gtk_vbox_new(false, 6); -+ gtk_box_pack_start(GTK_BOX(vbox),vbox1,false,false, 0); -+ GtkWidget *check_button = gtk_check_button_new_with_mnemonic(_("_Pronounce the word when it pops up.")); -+ bool pronounce_when_popup= -+ conf->get_bool_at("floating_window/pronounce_when_popup"); -+ -+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(check_button), -+ pronounce_when_popup); -+ g_signal_connect(G_OBJECT(check_button), "toggled", G_CALLBACK(on_setup_floatwin_pronounce_ckbutton_toggled), this); -+ gtk_box_pack_start(GTK_BOX(vbox1), check_button, FALSE, FALSE, 0); -+ -+ check_button = gtk_check_button_new_with_mnemonic(_("_Show floating window if word not found.")); -+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(check_button), conf->get_bool_at("floating_window/show_if_not_found")); -+ g_signal_connect(G_OBJECT(check_button), "toggled", G_CALLBACK(on_setup_show_float_if_not_found), this); -+ gtk_box_pack_start(GTK_BOX(vbox1), check_button, FALSE, FALSE, 0); -+} -+ -+#ifndef CONFIG_GPE -+void PrefsDlg::on_setup_floatwin_size_max_width_spinbutton_changed(GtkSpinButton *button, PrefsDlg *oPrefsDlg) -+{ -+ gint width = gtk_spin_button_get_value_as_int(button); -+ conf->set_int_at("floating_window/max_window_width", width); -+} -+ -+void PrefsDlg::on_setup_floatwin_size_max_height_spinbutton_changed(GtkSpinButton *button, PrefsDlg *oPrefsDlg) -+{ -+ gint height = gtk_spin_button_get_value_as_int(button); -+ conf->set_int_at("floating_window/max_window_height", height); -+} -+ -+void PrefsDlg::on_setup_floatwin_use_custom_bg_toggled(GtkToggleButton *button, PrefsDlg *oPrefsDlg) -+{ -+ gboolean use = gtk_toggle_button_get_active(button); -+ conf->set_bool_at("floating_window/use_custom_bg", use); -+ if (use) { -+ GdkColor color; -+ color.red = conf->get_int_at("floating_window/bg_red"); -+ color.green = conf->get_int_at("floating_window/bg_green"); -+ color.blue = conf->get_int_at("floating_window/bg_blue"); -+ gpAppFrame->oFloatWin.set_bg(&color); -+ } else { -+ gpAppFrame->oFloatWin.set_bg(NULL); -+ } -+} -+ -+void PrefsDlg::on_setup_floatwin_color_set(GtkColorButton *widget, PrefsDlg *oPrefsDlg) -+{ -+ GdkColor color; -+ gtk_color_button_get_color(widget, &color); -+ conf->set_int_at("floating_window/bg_red", color.red); -+ conf->set_int_at("floating_window/bg_green", color.green); -+ conf->set_int_at("floating_window/bg_blue", color.blue); -+ if (conf->get_bool_at("floating_window/use_custom_bg")) { -+ gpAppFrame->oFloatWin.set_bg(&color); -+ } -+} -+ -+void PrefsDlg::on_setup_floatwin_transparent_scale_changed(GtkRange *range, PrefsDlg *oPrefsDlg) -+{ -+ gint transparent = (gint)gtk_range_get_value(range); -+ conf->set_int_at("floating_window/transparent", transparent); -+ gtk_window_set_opacity(GTK_WINDOW(gpAppFrame->oFloatWin.FloatWindow), (100-transparent)/100.0); -+} -+ -+void PrefsDlg::setup_floatwin_size_page() -+{ -+ GtkWidget *vbox = prepare_page(GTK_NOTEBOOK(notebook), _("Settings"), GTK_STOCK_ZOOM_FIT); -+ GtkWidget *vbox1 = gtk_vbox_new(false, 6); -+ gtk_box_pack_start(GTK_BOX(vbox),vbox1,false,false, 0); -+ GtkWidget *table; -+ table = gtk_table_new(3, 2, FALSE); -+ gtk_table_set_row_spacings(GTK_TABLE(table), 6); -+ gtk_table_set_col_spacings(GTK_TABLE(table), 6); -+ gtk_box_pack_start(GTK_BOX(vbox1),table,false,false,0); -+ -+ int max_width= -+ conf->get_int_at("floating_window/max_window_width"); -+ int max_height= -+ conf->get_int_at("floating_window/max_window_height"); -+ -+ GdkScreen *screen = gtk_window_get_screen(parent_window); -+ gint screen_width = gdk_screen_get_width(screen); -+ gint screen_height = gdk_screen_get_height(screen); -+ -+ GtkWidget *label=gtk_label_new(NULL); -+ gtk_label_set_markup_with_mnemonic(GTK_LABEL(label), _("Max window _width:")); -+ gtk_table_attach(GTK_TABLE(table), label, 0, 1, 0, 1, GTK_FILL, GTK_FILL, 0, 0); -+ GtkWidget *spin_button; -+ spin_button = gtk_spin_button_new_with_range(MIN_MAX_FLOATWIN_WIDTH,screen_width,1); -+ gtk_label_set_mnemonic_widget(GTK_LABEL(label), spin_button); -+ gtk_spin_button_set_update_policy(GTK_SPIN_BUTTON(spin_button), GTK_UPDATE_IF_VALID); -+ gtk_spin_button_set_value(GTK_SPIN_BUTTON(spin_button), max_width); -+ g_signal_connect(G_OBJECT(spin_button), "value-changed", -+ G_CALLBACK(on_setup_floatwin_size_max_width_spinbutton_changed), this); -+ gtk_table_attach(GTK_TABLE(table), spin_button, 1, 2, 0, 1, GTK_FILL, GTK_FILL, 0, 0); -+ label=gtk_label_new(_("(default:320)")); -+ gtk_table_attach(GTK_TABLE(table), label, 2, 3, 0, 1, GTK_FILL, GTK_FILL, 0, 0); -+ -+ label=gtk_label_new(NULL); -+ gtk_label_set_markup_with_mnemonic(GTK_LABEL(label), _("Max window hei_ght:")); -+ gtk_table_attach(GTK_TABLE(table), label, 0, 1, 1, 2, GTK_FILL, GTK_FILL, 0, 0); -+ spin_button = gtk_spin_button_new_with_range(MIN_MAX_FLOATWIN_HEIGHT,screen_height,1); -+ gtk_label_set_mnemonic_widget(GTK_LABEL(label), spin_button); -+ gtk_spin_button_set_update_policy(GTK_SPIN_BUTTON(spin_button), GTK_UPDATE_IF_VALID); -+ gtk_spin_button_set_value(GTK_SPIN_BUTTON(spin_button), max_height); -+ g_signal_connect (G_OBJECT (spin_button), "value-changed", G_CALLBACK (on_setup_floatwin_size_max_height_spinbutton_changed), (gpointer)this); -+ gtk_table_attach(GTK_TABLE(table), spin_button, 1, 2, 1, 2, GTK_FILL, GTK_FILL, 0, 0); -+ label=gtk_label_new(_("(default:240)")); -+ gtk_table_attach(GTK_TABLE(table), label, 2, 3, 1, 2, GTK_FILL, GTK_FILL, 0, 0); -+ -+ GtkWidget*hbox1 = gtk_hbox_new(false, 5); -+ gtk_box_pack_start(GTK_BOX(vbox1),hbox1,false,false,0); -+ GtkWidget *check_button = gtk_check_button_new_with_mnemonic(_("_Use custom background color:")); -+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(check_button), conf->get_bool_at("floating_window/use_custom_bg")); -+ g_signal_connect(G_OBJECT(check_button), "toggled", G_CALLBACK(on_setup_floatwin_use_custom_bg_toggled), this); -+ gtk_box_pack_start(GTK_BOX(hbox1),check_button,false,false,0); -+ GdkColor color; -+ color.red = conf->get_int_at("floating_window/bg_red"); -+ color.green = conf->get_int_at("floating_window/bg_green"); -+ color.blue = conf->get_int_at("floating_window/bg_blue"); -+ GtkWidget *colorbutton = gtk_color_button_new_with_color(&color); -+ g_signal_connect(G_OBJECT(colorbutton), "color-set", G_CALLBACK(on_setup_floatwin_color_set), this); -+ gtk_box_pack_start(GTK_BOX(hbox1),colorbutton,false,false,0); -+ -+ GtkWidget *hbox = gtk_hbox_new(false, 5); -+ gtk_box_pack_start(GTK_BOX(vbox1),hbox,FALSE,FALSE, 0); -+ label=gtk_label_new(NULL); -+ gtk_label_set_markup_with_mnemonic(GTK_LABEL(label), _("_Transparency:")); -+ gtk_box_pack_start(GTK_BOX(hbox),label,FALSE,FALSE, 0); -+ GtkWidget *hscale; -+ hscale = gtk_hscale_new_with_range(0,80,1); -+ gtk_label_set_mnemonic_widget(GTK_LABEL(label), hscale); -+ int transparent=conf->get_int_at("floating_window/transparent"); -+ gtk_range_set_value(GTK_RANGE(hscale), transparent); -+ g_signal_connect(G_OBJECT(hscale), "value-changed", G_CALLBACK(on_setup_floatwin_transparent_scale_changed), this); -+ gtk_box_pack_start(GTK_BOX(hbox),hscale,TRUE,TRUE, 0); -+} -+#endif -+ -+GtkWidget* PrefsDlg::create_notebook () -+{ -+ notebook = gtk_notebook_new(); -+ GtkNotebook *nb = GTK_NOTEBOOK(notebook); -+#ifdef CONFIG_GPE -+ gtk_notebook_set_scrollable(nb, true); -+#else -+ gtk_notebook_set_show_tabs(nb,false); -+ gtk_notebook_set_show_border(nb,false); -+ setup_logo_page (); -+#endif -+ setup_dictionary_scan_page (); -+ setup_dictionary_font_page (); -+ setup_dictionary_cache_page (); -+ setup_dictionary_export_page (); -+ setup_dictionary_sound_page (); -+ setup_dict_article_rendering(); -+ setup_network_netdict(); -+ setup_mainwin_input_page (); -+ setup_mainwin_options_page (); -+ setup_mainwin_searchwebsite_page(); -+ setup_NotificationAreaIcon_options_page(); -+ setup_floatwin_options_page (); -+#ifdef CONFIG_GPE -+ gtk_notebook_set_current_page (nb, 0); -+#else -+ setup_floatwin_size_page (); -+ gtk_notebook_set_current_page (nb, LOGO); -+#endif -+ return notebook; -+} -+ -+ -+PrefsDlg::PrefsDlg(GtkWindow *parent, GdkPixbuf *logo, const std::list<std::string>& key_combs_) : -+ key_combs(key_combs_) -+{ -+ parent_window=parent; -+#ifndef CONFIG_GPE -+ stardict_logo=logo; -+#endif -+ -+ window = NULL; -+} -+ -+bool PrefsDlg::ShowModal() -+{ -+ window = gtk_dialog_new(); -+ gtk_window_set_transient_for(GTK_WINDOW(window), parent_window); -+ -+ gtk_dialog_add_button(GTK_DIALOG(window), -+ GTK_STOCK_HELP, -+ GTK_RESPONSE_HELP); -+ -+ gtk_dialog_add_button(GTK_DIALOG(window), -+ GTK_STOCK_CLOSE, -+ GTK_RESPONSE_CLOSE); -+ gtk_dialog_set_default_response(GTK_DIALOG(window), -+ GTK_RESPONSE_CLOSE); -+ g_signal_connect(G_OBJECT(window), "response", -+ G_CALLBACK(response_handler), this); -+#ifndef CONFIG_GPE -+ GtkWidget *hbox; -+ hbox = gtk_hbox_new (FALSE, 18); -+ gtk_container_set_border_width (GTK_CONTAINER (hbox), 10); -+ GtkWidget *r; -+ r = gtk_vbox_new (FALSE, 6); -+ -+ GtkWidget *label; -+ label = gtk_label_new_with_mnemonic (_("Cat_egories:")); -+ gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT); -+ g_object_set (G_OBJECT (label), "xalign", 0.0, NULL); -+ create_categories_tree(); -+ -+ -+ gtk_box_pack_start(GTK_BOX(r), label, FALSE, FALSE, 0); -+ gtk_box_pack_start(GTK_BOX(r), categories_window, TRUE, TRUE, 0); -+#endif -+ -+ GtkWidget *l = create_notebook (); -+ -+#ifdef CONFIG_GPE -+ gtk_box_pack_start (GTK_BOX (GTK_DIALOG (window)->vbox), l, true, true, 0); -+#else -+ gtk_box_pack_start (GTK_BOX (hbox), r, FALSE, FALSE, 0); -+ gtk_box_pack_start (GTK_BOX (hbox), l, TRUE, TRUE, 0); -+ gtk_box_pack_start (GTK_BOX (GTK_DIALOG (window)->vbox), hbox, true, true, 0); -+ gtk_label_set_mnemonic_widget (GTK_LABEL (label), categories_tree); -+#endif -+ -+ gtk_widget_show_all (GTK_DIALOG (window)->vbox); -+ gtk_window_set_title (GTK_WINDOW (window), _("Preferences")); -+ -+#ifndef CONFIG_GPE -+ resize_categories_tree(); -+#endif -+ gint result; -+ while ((result = gtk_dialog_run(GTK_DIALOG(window)))==GTK_RESPONSE_HELP) -+ ; -+ if (result != GTK_RESPONSE_NONE) { -+ const gchar *ch; -+ ch = gtk_entry_get_text(eExportFile); -+ if (ch[0]) -+ conf->set_string_at("dictionary/export_file", ch); -+#ifndef _WIN32 -+ ch = gtk_entry_get_text(eTTSCommandline); -+ if (ch[0]) { -+ conf->set_string("/apps/stardict/preferences/dictionary/tts_program_cmdline", ch); -+ gpAppFrame->oReadWord.tts_program_cmdline = ch; -+ } -+#endif -+ const gchar *server; -+ ch = gtk_entry_get_text(eStarDictServer); -+ if (ch[0]) -+ server = ch; -+ else -+ server = _("dict.stardict.org"); -+ conf->set_string_at("network/server", server); -+ int port; -+ ch = gtk_entry_get_text(eStarDictServerPort); -+ if (ch[0]) -+ port = atoi(ch); -+ else -+ port = 2628; -+ conf->set_int_at("network/port", port); -+ gpAppFrame->oStarDictClient.set_server(server, port); -+#if defined(CONFIG_GTK) || defined(CONFIG_GPE) -+ ch = gtk_entry_get_text(ePlayCommand); -+ if (ch[0]) -+ conf->set_string_at("dictionary/play_command", ch); -+#endif -+ GtkTextBuffer *text_view_buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(tts_textview)); -+ GtkTextIter start_iter; -+ GtkTextIter end_iter; -+ gtk_text_buffer_get_start_iter(text_view_buffer, &start_iter); -+ gtk_text_buffer_get_end_iter(text_view_buffer, &end_iter); -+ gchar *text = gtk_text_buffer_get_text(text_view_buffer, &start_iter, &end_iter, FALSE); -+ conf->set_string_at("dictionary/tts_path", text); -+ gpAppFrame->oReadWord.LoadRealTtsPath(text); -+ g_free(text); -+ gtk_widget_destroy(GTK_WIDGET(window)); -+ window = NULL; -+ return false; -+ } else { -+ return true; -+ } -+} -+ -+void PrefsDlg::Close() -+{ -+ if (window) { -+ gtk_widget_destroy (window); -+ window = NULL; -+ } -+} -+ -+#ifndef CONFIG_GPE -+void PrefsDlg::resize_categories_tree(void) -+{ -+ //this is hack for prevet horizontaly scrolling -+ //if you know how it make better, just write -+ GtkRequisition rtv, rsw; -+ gtk_widget_size_request(categories_tree, &rtv); -+ gtk_widget_size_request(GTK_SCROLLED_WINDOW(categories_window)->vscrollbar, &rsw); -+ gtk_widget_set_size_request(categories_window, rtv.width+rsw.width+25, -1); -+} -+#endif -diff -Nur stardict-3.0.1.orig//src/readword.cpp stardict-3.0.1/src/readword.cpp ---- stardict-3.0.1.orig//src/readword.cpp 2007-07-10 02:16:04.000000000 -0500 -+++ stardict-3.0.1/src/readword.cpp 2010-05-24 00:53:36.380667202 -0500 -@@ -3,6 +3,7 @@ - #endif - - #include <cstring> -+#include <cstdlib> - #include <string> - - #include <glib/gi18n.h> -diff -Nur stardict-3.0.1.orig//src/sigc++/signal.h stardict-3.0.1/src/sigc++/signal.h ---- stardict-3.0.1.orig//src/sigc++/signal.h 2007-07-10 02:16:01.000000000 -0500 -+++ stardict-3.0.1/src/sigc++/signal.h 2010-05-24 00:53:36.381666157 -0500 -@@ -18,7 +18,7 @@ - //Compilers, such as older versions of SUN Forte C++, that do not allow this also often - //do not allow a typedef to have the same name as a class in the typedef's definition. - //For Sun Forte CC 5.7 (SUN Workshop 10), comment this out to fix the build. -- #define SIGC_TYPEDEF_REDEFINE_ALLOWED 1 -+// #define SIGC_TYPEDEF_REDEFINE_ALLOWED 1 - #endif - - namespace sigc { -diff -Nur stardict-3.0.1.orig//src/utils.cpp stardict-3.0.1/src/utils.cpp ---- stardict-3.0.1.orig//src/utils.cpp 2007-10-21 21:25:02.000000000 -0500 -+++ stardict-3.0.1/src/utils.cpp 2010-05-24 00:53:36.381666157 -0500 -@@ -22,6 +22,8 @@ - # include "config.h" - #endif - -+#include <cstring> -+ - #include <glib.h> - #include <glib/gi18n.h> - #include <cstdlib> -diff -Nur stardict-3.0.1.orig//src/utils.cpp~ stardict-3.0.1/src/utils.cpp~ ---- stardict-3.0.1.orig//src/utils.cpp~ 1969-12-31 18:00:00.000000000 -0600 -+++ stardict-3.0.1/src/utils.cpp~ 2007-10-21 21:25:02.000000000 -0500 -@@ -0,0 +1,203 @@ -+/* -+ * This file part of StarDict - A international dictionary for GNOME. -+ * http://stardict.sourceforge.net -+ * Copyright (C) 2005-2006 Evgeniy <dushistov@mail.ru> -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 3 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU Library General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -+ */ -+ -+#ifdef HAVE_CONFIG_H -+# include "config.h" -+#endif -+ -+#include <glib.h> -+#include <glib/gi18n.h> -+#include <cstdlib> -+#include <gtk/gtk.h> -+ -+#ifdef CONFIG_GNOME -+# include <libgnome/libgnome.h> -+# include <libgnomeui/libgnomeui.h> -+#elif defined(_WIN32) -+# include <gdk/gdkwin32.h> -+#endif -+ -+#include "utils.h" -+ -+ -+void ProcessGtkEvent() -+{ -+ while (gtk_events_pending()) -+ gtk_main_iteration(); -+} -+ -+std::string get_user_config_dir() -+{ -+ const gchar *config_path_from_env = g_getenv("STARDICT_CONFIG_PATH"); -+ if (config_path_from_env) -+ return config_path_from_env; -+#ifdef _WIN32 -+ std::string res = g_get_user_config_dir(); -+ res += G_DIR_SEPARATOR_S "StarDict"; -+ return res; -+#else -+ std::string res; -+ gchar *tmp = g_build_filename(g_get_home_dir(), ".stardict", NULL); -+ res=tmp; -+ g_free(tmp); -+ return res; -+#endif -+} -+ -+std::string combnum2str(gint comb_code) -+{ -+ switch (comb_code) { -+#ifdef _WIN32 -+ case 0: -+ return "Shift"; -+ case 1: -+ return "Alt"; -+ case 2: -+ return "Ctrl"; -+ case 3: -+ return "Ctrl+Alt"; -+#else -+ case 0: -+ return "Win"; -+ case 1: -+ return "Shift"; -+ case 2: -+ return "Alt"; -+ case 3: -+ return "Ctrl"; -+ case 4: -+ return "Ctrl+Alt"; -+ case 5: -+ return "Ctrl+e"; -+ case 6: -+ return "F1"; -+ case 7: -+ return "F2"; -+ case 8: -+ return "F3"; -+ case 9: -+ return "F4"; -+#endif -+ default: -+ return ""; -+ } -+} -+ -+std::vector<std::string> split(const std::string& str, char sep) -+{ -+ std::vector<std::string> res; -+ std::string::size_type prev_pos=0, pos = 0; -+ while ((pos=str.find(sep, prev_pos))!=std::string::npos) { -+ res.push_back(std::string(str, prev_pos, pos-prev_pos)); -+ prev_pos=pos+1; -+ } -+ res.push_back(std::string(str, prev_pos, str.length()-prev_pos)); -+ -+ return res; -+} -+ -+GdkPixbuf *load_image_from_file(const std::string& filename) -+{ -+ GError *err=NULL; -+ GdkPixbuf *res=gdk_pixbuf_new_from_file(filename.c_str(), &err); -+ if (!res) { -+ GtkWidget *message_dlg = -+ gtk_message_dialog_new( -+ NULL, -+ (GtkDialogFlags)(GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT), -+ GTK_MESSAGE_ERROR, -+ GTK_BUTTONS_OK, -+ _("Can not load image. %s"), err->message); -+ -+ gtk_dialog_set_default_response(GTK_DIALOG(message_dlg), GTK_RESPONSE_OK); -+ -+ gtk_window_set_resizable(GTK_WINDOW(message_dlg), FALSE); -+ -+ gtk_dialog_run(GTK_DIALOG(message_dlg)); -+ gtk_widget_destroy(message_dlg); -+ g_error_free(err); -+ exit(EXIT_FAILURE); -+ } -+ -+ return res; -+} -+ -+static gchar * byte_to_hex(unsigned char nr) { -+ gchar *result = NULL; -+ -+ result = g_strdup_printf("%%%x%x", nr / 0x10, nr % 0x10); -+ return result; -+} -+ -+char *common_encode_uri_string(const char *string) -+{ -+ gchar *newURIString; -+ gchar *hex, *tmp = NULL; -+ int i, j, len, bytes; -+ -+ /* the UTF-8 string is casted to ASCII to treat -+ the characters bytewise and convert non-ASCII -+ compatible chars to URI hexcodes */ -+ newURIString = g_strdup(""); -+ len = strlen(string); -+ for(i = 0; i < len; i++) { -+ if(g_ascii_isalnum(string[i]) || strchr("-_.!~*'()", (int)string[i])) -+ tmp = g_strdup_printf("%s%c", newURIString, string[i]); -+ else if(string[i] == ' ') -+ tmp = g_strdup_printf("%s%%20", newURIString); -+ else if((unsigned char)string[i] <= 127) { -+ tmp = g_strdup_printf("%s%s", newURIString, hex = byte_to_hex(string[i]));g_free(hex); -+ } else { -+ bytes = 0; -+ if(((unsigned char)string[i] >= 192) && ((unsigned char)string[i] <= 223)) -+ bytes = 2; -+ else if(((unsigned char)string[i] > 223) && ((unsigned char)string[i] <= 239)) -+ bytes = 3; -+ else if(((unsigned char)string[i] > 239) && ((unsigned char)string[i] <= 247)) -+ bytes = 4; -+ else if(((unsigned char)string[i] > 247) && ((unsigned char)string[i] <= 251)) -+ bytes = 5; -+ else if(((unsigned char)string[i] > 247) && ((unsigned char)string[i] <= 251)) -+ bytes = 6; -+ -+ if(0 != bytes) { -+ if((i + (bytes - 1)) > len) { -+ g_warning(("Unexpected end of character sequence or corrupt UTF-8 encoding! Some characters were dropped!")); -+ break; -+ } -+ -+ for(j=0; j < (bytes - 1); j++) { -+ tmp = g_strdup_printf("%s%s", newURIString, hex = byte_to_hex((unsigned char)string[i++])); -+ g_free(hex); -+ g_free(newURIString); -+ newURIString = tmp; -+ } -+ tmp = g_strdup_printf("%s%s", newURIString, hex = byte_to_hex((unsigned char)string[i])); -+ g_free(hex); -+ } else { -+ /* sh..! */ -+ g_error("Internal error while converting UTF-8 chars to HTTP URI!"); -+ } -+ } -+ g_free(newURIString); -+ newURIString = tmp; -+ } -+ return newURIString; -+} -diff -Nur stardict-3.0.1.orig//src/x11_iskeyspressed.hpp stardict-3.0.1/src/x11_iskeyspressed.hpp ---- stardict-3.0.1.orig//src/x11_iskeyspressed.hpp 2007-07-10 02:16:04.000000000 -0500 -+++ stardict-3.0.1/src/x11_iskeyspressed.hpp 2010-05-24 00:53:36.381666157 -0500 -@@ -1,6 +1,8 @@ - #ifndef _X11_ISKEYSPRESSED_HPP_ - #define _X11_ISKEYSPRESSED_HPP_ - -+#include <memory> -+ - #include <gdk/gdkx.h> - #include <X11/keysym.h> - #include <gtk/gtk.h> -diff -Nur stardict-3.0.1.orig//stardict-plugins/stardict-dictdotcn-plugin/stardict_dictdotcn.cpp stardict-3.0.1/stardict-plugins/stardict-dictdotcn-plugin/stardict_dictdotcn.cpp ---- stardict-3.0.1.orig//stardict-plugins/stardict-dictdotcn-plugin/stardict_dictdotcn.cpp 2007-10-10 04:28:29.000000000 -0500 -+++ stardict-3.0.1/stardict-plugins/stardict-dictdotcn-plugin/stardict_dictdotcn.cpp 2010-05-24 00:53:36.381666157 -0500 -@@ -1,6 +1,6 @@ - #include "stardict_dictdotcn.h" - #include <glib/gi18n.h> --#include <string> -+#include <cstring> - #include <list> - - #ifdef _WIN32 -diff -Nur stardict-3.0.1.orig//stardict-plugins/stardict-espeak-tts-plugin/stardict_espeak.cpp stardict-3.0.1/stardict-plugins/stardict-espeak-tts-plugin/stardict_espeak.cpp ---- stardict-3.0.1.orig//stardict-plugins/stardict-espeak-tts-plugin/stardict_espeak.cpp 2007-09-19 03:27:18.000000000 -0500 -+++ stardict-3.0.1/stardict-plugins/stardict-espeak-tts-plugin/stardict_espeak.cpp 2010-05-24 00:53:36.382665737 -0500 -@@ -1,4 +1,5 @@ - #include "stardict_espeak.h" -+#include <cstring> - #include <espeak/speak_lib.h> - #include <glib/gi18n.h> - -diff -Nur stardict-3.0.1.orig//stardict-plugins/stardict-gucharmap-plugin/stardict_gucharmap.cpp stardict-3.0.1/stardict-plugins/stardict-gucharmap-plugin/stardict_gucharmap.cpp ---- stardict-3.0.1.orig//stardict-plugins/stardict-gucharmap-plugin/stardict_gucharmap.cpp 2007-08-31 02:10:41.000000000 -0500 -+++ stardict-3.0.1/stardict-plugins/stardict-gucharmap-plugin/stardict_gucharmap.cpp 2010-05-24 00:53:36.382665737 -0500 -@@ -1,7 +1,8 @@ - #include "stardict_gucharmap.h" - #include <glib/gi18n.h> - #include <gucharmap/gucharmap.h> --#include <string> -+#include <cstring> -+#include <cstdlib> - - static char *build_dictdata(char type, const char *definition) - { -diff -Nur stardict-3.0.1.orig//stardict-plugins/stardict-html-parsedata-plugin/stardict_html_parsedata.cpp stardict-3.0.1/stardict-plugins/stardict-html-parsedata-plugin/stardict_html_parsedata.cpp ---- stardict-3.0.1.orig//stardict-plugins/stardict-html-parsedata-plugin/stardict_html_parsedata.cpp 2007-09-13 02:51:55.000000000 -0500 -+++ stardict-3.0.1/stardict-plugins/stardict-html-parsedata-plugin/stardict_html_parsedata.cpp 2010-05-24 00:53:36.382665737 -0500 -@@ -1,4 +1,6 @@ - #include "stardict_html_parsedata.h" -+#include <cstring> -+#include <cstdlib> - #include <glib/gi18n.h> - - #ifdef _WIN32 -diff -Nur stardict-3.0.1.orig//stardict-plugins/stardict-man-plugin/stardict_man.cpp stardict-3.0.1/stardict-plugins/stardict-man-plugin/stardict_man.cpp ---- stardict-3.0.1.orig//stardict-plugins/stardict-man-plugin/stardict_man.cpp 2007-09-19 03:30:54.000000000 -0500 -+++ stardict-3.0.1/stardict-plugins/stardict-man-plugin/stardict_man.cpp 2010-05-24 00:53:36.382665737 -0500 -@@ -1,6 +1,6 @@ - #include "stardict_man.h" - #include <glib/gi18n.h> --#include <string> -+#include <cstring> - - static const StarDictPluginSystemInfo *plugin_info = NULL; - static bool need_prefix; -diff -Nur stardict-3.0.1.orig//stardict-plugins/stardict-powerword-parsedata-plugin/stardict_powerword_parsedata.cpp stardict-3.0.1/stardict-plugins/stardict-powerword-parsedata-plugin/stardict_powerword_parsedata.cpp ---- stardict-3.0.1.orig//stardict-plugins/stardict-powerword-parsedata-plugin/stardict_powerword_parsedata.cpp 2007-10-25 03:16:37.000000000 -0500 -+++ stardict-3.0.1/stardict-plugins/stardict-powerword-parsedata-plugin/stardict_powerword_parsedata.cpp 2010-05-24 00:53:36.382665737 -0500 -@@ -1,4 +1,5 @@ - #include "stardict_powerword_parsedata.h" -+#include <cstring> - #include <glib/gi18n.h> - - #ifdef _WIN32 -diff -Nur stardict-3.0.1.orig//stardict-plugins/stardict-qqwry-plugin/stardict_qqwry.cpp stardict-3.0.1/stardict-plugins/stardict-qqwry-plugin/stardict_qqwry.cpp ---- stardict-3.0.1.orig//stardict-plugins/stardict-qqwry-plugin/stardict_qqwry.cpp 2007-11-02 03:41:26.000000000 -0500 -+++ stardict-3.0.1/stardict-plugins/stardict-qqwry-plugin/stardict_qqwry.cpp 2010-05-24 00:53:36.382665737 -0500 -@@ -1,7 +1,8 @@ - #include "stardict_qqwry.h" - #include <glib/gi18n.h> - #include <glib/gstdio.h> --#include <string> -+#include <cstring> -+#include <cstdlib> - - #ifdef _WIN32 - #include <windows.h> -diff -Nur stardict-3.0.1.orig//stardict-plugins/stardict-spell-plugin/stardict_spell.cpp stardict-3.0.1/stardict-plugins/stardict-spell-plugin/stardict_spell.cpp ---- stardict-3.0.1.orig//stardict-plugins/stardict-spell-plugin/stardict_spell.cpp 2007-09-19 03:29:21.000000000 -0500 -+++ stardict-3.0.1/stardict-plugins/stardict-spell-plugin/stardict_spell.cpp 2010-05-24 00:53:36.383666084 -0500 -@@ -1,4 +1,5 @@ - #include "stardict_spell.h" -+#include <cstring> - #include <glib.h> - #include <glib/gi18n.h> - #include <enchant.h> -diff -Nur stardict-3.0.1.orig//stardict-plugins/stardict-wiki-parsedata-plugin/stardict_wiki2xml.cpp stardict-3.0.1/stardict-plugins/stardict-wiki-parsedata-plugin/stardict_wiki2xml.cpp ---- stardict-3.0.1.orig//stardict-plugins/stardict-wiki-parsedata-plugin/stardict_wiki2xml.cpp 2007-07-10 02:16:15.000000000 -0500 -+++ stardict-3.0.1/stardict-plugins/stardict-wiki-parsedata-plugin/stardict_wiki2xml.cpp 2010-05-24 00:53:36.383666084 -0500 -@@ -1,5 +1,6 @@ - #include "stardict_wiki2xml.h" - #include "WIKI2XML.h" -+#include <cstring> - #include <glib.h> - - std::string wiki2xml(std::string &str) -diff -Nur stardict-3.0.1.orig//stardict-plugins/stardict-wiki-parsedata-plugin/stardict_wiki_parsedata.cpp stardict-3.0.1/stardict-plugins/stardict-wiki-parsedata-plugin/stardict_wiki_parsedata.cpp ---- stardict-3.0.1.orig//stardict-plugins/stardict-wiki-parsedata-plugin/stardict_wiki_parsedata.cpp 2007-08-31 01:41:21.000000000 -0500 -+++ stardict-3.0.1/stardict-plugins/stardict-wiki-parsedata-plugin/stardict_wiki_parsedata.cpp 2010-05-24 00:53:36.383666084 -0500 -@@ -1,5 +1,6 @@ - #include "stardict_wiki_parsedata.h" - #include "stardict_wiki2xml.h" -+#include <cstring> - #include <glib/gi18n.h> - - #ifdef _WIN32 -diff -Nur stardict-3.0.1.orig//stardict-plugins/stardict-wordnet-plugin/court_widget.cpp stardict-3.0.1/stardict-plugins/stardict-wordnet-plugin/court_widget.cpp ---- stardict-3.0.1.orig//stardict-plugins/stardict-wordnet-plugin/court_widget.cpp 2007-10-17 20:36:22.000000000 -0500 -+++ stardict-3.0.1/stardict-plugins/stardict-wordnet-plugin/court_widget.cpp 2010-05-24 00:53:36.383666084 -0500 -@@ -1,4 +1,5 @@ - #include "court_widget.h" -+#include <cstring> - #include <math.h> - #include <list> - -diff -Nur stardict-3.0.1.orig//stardict-plugins/stardict-wordnet-plugin/stardict_wordnet.cpp stardict-3.0.1/stardict-plugins/stardict-wordnet-plugin/stardict_wordnet.cpp ---- stardict-3.0.1.orig//stardict-plugins/stardict-wordnet-plugin/stardict_wordnet.cpp 2007-10-14 22:32:04.000000000 -0500 -+++ stardict-3.0.1/stardict-plugins/stardict-wordnet-plugin/stardict_wordnet.cpp 2010-05-24 00:53:36.383666084 -0500 -@@ -1,5 +1,6 @@ - #include "stardict_wordnet.h" - #include "court_widget.h" -+#include <cstring> - #include <glib/gi18n.h> - - #ifdef _WIN32 -diff -Nur stardict-3.0.1.orig//stardict-plugins/stardict-wordnet-plugin/stardict_wordnet_parsedata.cpp stardict-3.0.1/stardict-plugins/stardict-wordnet-plugin/stardict_wordnet_parsedata.cpp ---- stardict-3.0.1.orig//stardict-plugins/stardict-wordnet-plugin/stardict_wordnet_parsedata.cpp 2007-10-10 04:39:10.000000000 -0500 -+++ stardict-3.0.1/stardict-plugins/stardict-wordnet-plugin/stardict_wordnet_parsedata.cpp 2010-05-24 00:53:36.383666084 -0500 -@@ -1,4 +1,5 @@ - #include "stardict_wordnet_parsedata.h" -+#include <cstring> - #include <glib/gi18n.h> - - #ifdef _WIN32 -diff -Nur stardict-3.0.1.orig//stardict-plugins/stardict-xdxf-parsedata-plugin/stardict_xdxf_parsedata.cpp stardict-3.0.1/stardict-plugins/stardict-xdxf-parsedata-plugin/stardict_xdxf_parsedata.cpp ---- stardict-3.0.1.orig//stardict-plugins/stardict-xdxf-parsedata-plugin/stardict_xdxf_parsedata.cpp 2007-08-31 01:41:54.000000000 -0500 -+++ stardict-3.0.1/stardict-plugins/stardict-xdxf-parsedata-plugin/stardict_xdxf_parsedata.cpp 2010-05-24 00:53:36.384665734 -0500 -@@ -1,4 +1,5 @@ - #include "stardict_xdxf_parsedata.h" -+#include <cstring> - #include <glib/gi18n.h> - - #ifdef _WIN32 -diff -Nur stardict-3.0.1.orig//tests/t_config_file.cpp stardict-3.0.1/tests/t_config_file.cpp ---- stardict-3.0.1.orig//tests/t_config_file.cpp 2007-07-10 02:16:04.000000000 -0500 -+++ stardict-3.0.1/tests/t_config_file.cpp 2010-05-24 00:53:36.384665734 -0500 -@@ -8,6 +8,7 @@ - #include <cstring> - #include <iterator> - #include <iostream> -+#include <memory> - #include <gtk/gtk.h> - - #include "config_file.hpp" -diff -Nur stardict-3.0.1.orig//tests/t_xml.cpp stardict-3.0.1/tests/t_xml.cpp ---- stardict-3.0.1.orig//tests/t_xml.cpp 2007-07-10 02:16:04.000000000 -0500 -+++ stardict-3.0.1/tests/t_xml.cpp 2010-05-24 00:53:36.384665734 -0500 -@@ -5,6 +5,7 @@ - #include <glib.h> - #include <cstdlib> - #include <string> -+#include <cstring> - - - static void xml_decode(const char *str, std::string& decoded) diff --git a/misc/stardict/patches/stardict-3.0.1-gcc47.patch b/misc/stardict/patches/stardict-3.0.1-gcc47.patch deleted file mode 100644 index ddd22f819171..000000000000 --- a/misc/stardict/patches/stardict-3.0.1-gcc47.patch +++ /dev/null @@ -1,24 +0,0 @@ -diff --git a/src/sigc++/signal_base.h b/src/sigc++/signal_base.h -index 582a8f4..0d77ac5 100644 ---- a/src/sigc++/signal_base.h -+++ b/src/sigc++/signal_base.h -@@ -21,6 +21,7 @@ - #ifndef _SIGC_SIGNAL_BASE_H_ - #define _SIGC_SIGNAL_BASE_H_ - -+#include <cstddef> - #include <list> - #include <sigc++config.h> - #include <sigc++/type_traits.h> -diff --git a/stardict-plugins/stardict-wordnet-plugin/scene.hpp b/stardict-plugins/stardict-wordnet-plugin/scene.hpp -index 54003ca..270b2e2 100644 ---- a/stardict-plugins/stardict-wordnet-plugin/scene.hpp -+++ b/stardict-plugins/stardict-wordnet-plugin/scene.hpp -@@ -9,6 +9,7 @@ - #include "partic.hpp" - #include "spring.hpp" - -+#include <cstdlib> - #include <vector> - using namespace std; - diff --git a/misc/stardict/patches/stardict-transparent.patch b/misc/stardict/patches/stardict-transparent.patch deleted file mode 100644 index 1f4c149d522f..000000000000 --- a/misc/stardict/patches/stardict-transparent.patch +++ /dev/null @@ -1,101 +0,0 @@ -Index: src/eggtrayicon.c -=================================================================== ---- src/eggtrayicon.c (revision 248) -+++ src/eggtrayicon.c (working copy) -@@ -66,6 +66,8 @@ - - static void egg_tray_icon_realize (GtkWidget *widget); - static void egg_tray_icon_unrealize (GtkWidget *widget); -+static void egg_tray_icon_add (GtkContainer *container, -+ GtkWidget *widget); - - #ifdef GDK_WINDOWING_X11 - static void egg_tray_icon_update_manager_window (EggTrayIcon *icon, -@@ -113,6 +115,7 @@ - { - GObjectClass *gobject_class = (GObjectClass *)klass; - GtkWidgetClass *widget_class = (GtkWidgetClass *)klass; -+ GtkContainerClass *container_class = (GtkContainerClass *)klass; - - parent_class = g_type_class_peek_parent (klass); - -@@ -121,6 +124,8 @@ - widget_class->realize = egg_tray_icon_realize; - widget_class->unrealize = egg_tray_icon_unrealize; - -+ container_class->add = egg_tray_icon_add; -+ - g_object_class_install_property (gobject_class, - PROP_ORIENTATION, - g_param_spec_enum ("orientation", -@@ -159,8 +164,37 @@ - } - - #ifdef GDK_WINDOWING_X11 -+static gboolean -+transparent_expose_event (GtkWidget *widget, GdkEventExpose *event, gpointer user_data) -+{ -+ gdk_window_clear_area (widget->window, event->area.x, event->area.y, -+ event->area.width, event->area.height); -+ return FALSE; -+} - - static void -+make_transparent_again (GtkWidget *widget, GtkStyle *previous_style, -+ gpointer user_data) -+{ -+ gdk_window_set_back_pixmap(widget->window, NULL, TRUE); -+} -+ -+static void -+make_transparent (GtkWidget *widget, gpointer user_data) -+{ -+ if (GTK_WIDGET_NO_WINDOW (widget) || GTK_WIDGET_APP_PAINTABLE (widget)) -+ return; -+ -+ gtk_widget_set_app_paintable (widget, TRUE); -+ gtk_widget_set_double_buffered (widget, FALSE); -+ gdk_window_set_back_pixmap (widget->window, NULL, TRUE); -+ g_signal_connect (widget, "expose_event", -+ G_CALLBACK (transparent_expose_event), NULL); -+ g_signal_connect_after (widget, "style_set", -+ G_CALLBACK (make_transparent_again), NULL); -+} -+ -+static void - egg_tray_icon_get_orientation_property (EggTrayIcon *icon) - { - Display *xdisplay; -@@ -238,10 +272,22 @@ - } - return GDK_FILTER_CONTINUE; - } -- -+#else -+static void -+make_transparent (GtkWidget *widget, gpointer user_data) -+{ -+} - #endif - - static void -+egg_tray_icon_add (GtkContainer *container, GtkWidget *widget) -+{ -+ g_signal_connect (widget, "realize", -+ G_CALLBACK (make_transparent), NULL); -+ GTK_CONTAINER_CLASS (parent_class)->add (container, widget); -+} -+ -+static void - egg_tray_icon_unrealize (GtkWidget *widget) - { - #ifdef GDK_WINDOWING_X11 -@@ -381,6 +427,8 @@ - if (GTK_WIDGET_CLASS (parent_class)->realize) - GTK_WIDGET_CLASS (parent_class)->realize (widget); - -+ make_transparent (widget, NULL); -+ - screen = gtk_widget_get_screen (widget); - display = gdk_screen_get_display (screen); - xdisplay = gdk_x11_display_get_xdisplay (display); diff --git a/misc/stardict/stardict.SlackBuild b/misc/stardict/stardict.SlackBuild index a5f01d5ca9e7..4312cab8c443 100644 --- a/misc/stardict/stardict.SlackBuild +++ b/misc/stardict/stardict.SlackBuild @@ -27,14 +27,14 @@ cd $(dirname $0) ; CWD=$(pwd) PRGNAM=stardict -VERSION=${VERSION:-3.0.6} +VERSION=${VERSION:-3.0.6.2} BUILD=${BUILD:-1} TAG=${TAG:-_SBo} PKGTYPE=${PKGTYPE:-tgz} if [ -z "$ARCH" ]; then case "$( uname -m )" in - i?86) ARCH=i486 ;; + i?86) ARCH=i586 ;; arm*) ARCH=arm ;; *) ARCH=$( uname -m ) ;; esac @@ -54,8 +54,8 @@ OUTPUT=${OUTPUT:-/tmp} DOCS="AUTHORS COPYING ChangeLog INSTALL README" -if [ "$ARCH" = "i486" ]; then - SLKCFLAGS="-O2 -march=i486 -mtune=i686" +if [ "$ARCH" = "i586" ]; then + SLKCFLAGS="-O2 -march=i586 -mtune=i686" LIBDIRSUFFIX="" elif [ "$ARCH" = "i686" ]; then SLKCFLAGS="-O2 -march=i686 -mtune=i686" @@ -74,7 +74,7 @@ rm -rf $PKG mkdir -p $TMP $PKG $OUTPUT cd $TMP rm -rf $PRGNAM-$VERSION -tar xvf $CWD/$PRGNAM-$VERSION.tar.bz2 +tar xf $CWD/$PRGNAM-$VERSION-github-2.tar.?z* cd $PRGNAM-$VERSION chown -R root:root . find -L . \ @@ -83,6 +83,14 @@ find -L . \ \( -perm 666 -o -perm 664 -o -perm 640 -o -perm 600 -o -perm 444 \ -o -perm 440 -o -perm 400 \) -exec chmod 644 {} \; +sed -i 's/, enchant/, enchant-2/' dict/configure.ac +sed -i '/AM_GCONF_SOURCE_2/d' dict/configure.ac +sed -i '/GNOME_DOC_INIT/d' dict/configure.ac +sed -i '/gnome-doc-utils.make/d' dict/help/Makefile.am + +./autogen.sh +( cd dict ; ./autogen.sh ) + CFLAGS="$SLKCFLAGS" \ CXXFLAGS="$SLKCFLAGS -std=c++11" \ ./configure \ @@ -94,6 +102,7 @@ CXXFLAGS="$SLKCFLAGS -std=c++11" \ --docdir=/usr/doc/$PRGNAM-$VERSION \ --disable-gucharmap \ --disable-festival \ + --disable-flite \ --disable-espeak \ --disable-gnome-support \ --disable-schemas-install \ @@ -101,6 +110,7 @@ CXXFLAGS="$SLKCFLAGS -std=c++11" \ --disable-static \ --build=$ARCH-slackware-linux +sed -e 's/ -shared / -Wl,-O1,--as-needed\0/g' -i {dict,lib,tools}/libtool make make install DESTDIR=$PKG diff --git a/misc/stardict/stardict.info b/misc/stardict/stardict.info index 52811dcb62a3..c791df0d0eef 100644 --- a/misc/stardict/stardict.info +++ b/misc/stardict/stardict.info @@ -1,8 +1,8 @@ PRGNAM="stardict" -VERSION="3.0.6" +VERSION="3.0.6.2" HOMEPAGE="http://stardict-4.sourceforge.net/" -DOWNLOAD="http://sourceforge.net/projects/stardict-4/files/3.0.6/stardict-3.0.6.tar.bz2" -MD5SUM="93371b35482e6380e8bd4ba5d256b864" +DOWNLOAD="http://downloads.sourceforge.net/stardict-4/stardict-3.0.6.2-github-2.tar.xz" +MD5SUM="bd16a483917f4ff356370feaf2bb8347" DOWNLOAD_x86_64="" MD5SUM_x86_64="" REQUIRES="rarian" |