summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSuren A. Chilingaryan <csa@dside.dyndns.org>2005-07-29 03:26:28 +0000
committerSuren A. Chilingaryan <csa@dside.dyndns.org>2005-07-29 03:26:28 +0000
commite3f702e83a26468ee44f3f342a7a40a252f4603c (patch)
tree5ff76e9d11a9fdbdb493683d0f0840f46c67b6f8
parentcfaef1b6c9f33fbaa114628cf513d129bdff3c1c (diff)
downloadlibrcc-e3f702e83a26468ee44f3f342a7a40a252f4603c.tar.gz
librcc-e3f702e83a26468ee44f3f342a7a40a252f4603c.tar.bz2
librcc-e3f702e83a26468ee44f3f342a7a40a252f4603c.tar.xz
librcc-e3f702e83a26468ee44f3f342a7a40a252f4603c.zip
Translation
- Language Translation using libtranslate is implemented - Autoengine sets current charset (option)
-rw-r--r--Makefile.am2
-rw-r--r--README9
-rw-r--r--ToDo20
-rw-r--r--VERSION2
-rw-r--r--configure.in42
-rw-r--r--examples/Makefile.am12
-rw-r--r--examples/example1.c (renamed from examples/example.c)0
-rw-r--r--examples/example2.c60
-rw-r--r--examples/rcc-gtk-config.c6
-rw-r--r--external/Makefile.am12
-rw-r--r--external/rccexternal.c117
-rw-r--r--external/rcclibtranslate.c286
-rw-r--r--external/rcclibtranslate.h9
-rw-r--r--src/Makefile.am2
-rw-r--r--src/fs.c2
-rw-r--r--src/librcc.c45
-rw-r--r--src/librcc.h58
-rw-r--r--src/lngconfig.c7
-rw-r--r--src/lngconfig.h4
-rw-r--r--src/rccconfig.c6
-rw-r--r--src/rccdb4.c41
-rw-r--r--src/rccdb4.h8
-rw-r--r--src/rccexternal.c210
-rw-r--r--src/rccexternal.h35
-rw-r--r--src/rcciconv.c23
-rw-r--r--src/rcciconv.h14
-rw-r--r--src/rcctranslate.c151
-rw-r--r--src/rcctranslate.h31
-rw-r--r--src/recode.c68
-rw-r--r--ui/librccui.c28
-rw-r--r--ui/rccnames.c3
31 files changed, 1213 insertions, 100 deletions
diff --git a/Makefile.am b/Makefile.am
index e4d2e40..d5b909f 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -1,4 +1,4 @@
-SUBDIRS = src engines ui
+SUBDIRS = src engines external ui
EXTRA_DIST = librcd.spec
ACLOCAL_AMFLAGS = -I m4
diff --git a/README b/README
index 64e510c..e69de29 100644
--- a/README
+++ b/README
@@ -1,9 +0,0 @@
-Library for autoconversion of charsets to/from UTF-8.
-
- class = charset class
- engine = auto engine
- selected - which is selected
- current - resolves default values
-
-icnv = NULL - conversion isn't required
-icnv->icnv = (iconv_t)-1 - problem
diff --git a/ToDo b/ToDo
index 3957198..8167c92 100644
--- a/ToDo
+++ b/ToDo
@@ -1,4 +1,16 @@
-* Provide way to add to all languages several default Unicode encodings (UTF8, UTF16, UTF16BE)
-* Special type of classes to select only from Unicode encodings (or even just specified subset of encodings)
-* Multibyte(not-UTF8) support for FS classes
-* SetBufferSize ( 0 - autogrow )
+0.2.x:
+ - Common encodings:
+ + Provide way to add to all languages several default Unicode encodings (UTF8, UTF16, UTF16BE)
+ + Special type of classes to select only from Unicode encodings (or even just specified subset of encodings)
+ + Special pluggable encodings. For example translate to english.
+ * rccToEncoding(current_language, *new_language, buf, size)?
+ * rccFromEncoding(current_language, utf8_language, buf, size)?
+ * Code some options in charset name. (SpecialEncodingPrefix_Encoding_EncodingOptions)
+ - Buffer managment:
+ + SetBufferSize ( 0 - autogrow )
+ - Language autodetection
+ + Using spellchecker (aspell)
+ - Look on ofline translation libraries
+
+on request:
+ - Multibyte(not-UTF8) support for FS classes
diff --git a/VERSION b/VERSION
index d917d3e..0b8e116 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-0.1.2
+0.1.3CVS
diff --git a/configure.in b/configure.in
index 1be9411..b833095 100644
--- a/configure.in
+++ b/configure.in
@@ -33,6 +33,11 @@ AC_ARG_ENABLE( force-dynamic-engines,
[ --enable-force-dynamic-engines force usage of dynamic engines],,
enable_force_dynamic_engines="no")
+AC_ARG_ENABLE( libtranslate,
+ [ --disable-libtranslate disable usage of libtranslate],,
+ disable_libtranslate="yes")
+
+
AC_PROG_CC
AC_PROG_INSTALL
AM_PROG_LIBTOOL
@@ -49,7 +54,7 @@ AC_PATH_PROG(TAR, tar, /bin/tar)
dnl Checks for header files.
AC_CHECK_HEADERS(iconv.h,, [AC_MSG_ERROR(Missing iconv header)])
-AC_CHECK_HEADERS(mntent.h pwd.h sys/types.h sys/stat.h sys/file.h unistd.h fcntl.h)
+AC_CHECK_HEADERS(mntent.h pwd.h sys/types.h sys/stat.h sys/file.h sys/socket.h sys/un.h sys/time.h sys/select.h sys/wait.h signal.h unistd.h fcntl.h)
AC_TRY_COMPILE([#include <langinfo.h>],
[char *codeset = nl_langinfo (CODESET);],
@@ -102,6 +107,7 @@ ENCA_LIBS=""
ENCA_INCLUDES=""
HAVE_ENCA=no
+
if test "x$enable_force_dynamic_engines" != "xyes"; then
AC_CHECK_HEADER(librcd.h, [AC_CHECK_LIB(rcd, rcdGetRussianCharset, [
AC_DEFINE(HAVE_RCD,1,[Defines if libRCD is available])
@@ -157,6 +163,36 @@ AX_PATH_BDB([4],[
AC_SUBST(BDB_LIBS)
AC_SUBST(BDB_INCLUDES)
+PKG_CHECK_MODULES(GLIB2, glib-2.0 >= 2.0.0, HAVE_GLIB2=yes, HAVE_GLIB2=no)
+AM_CONDITIONAL(HAVE_GLIB2, [ test $HAVE_GLIB2 = yes ])
+
+
+if test "x$disable_libtranslate" != "xyes"; then
+ HAVE_LIBTRANSLATE=no
+ HAVE_LIBTRANSLATE_TIMED_TRANSLATE=no
+ LIBTRANSLATE_LIBS=""
+ LIBTRANSLATE_CFLAGS=""
+ AC_SUBST(LIBTRANSLATE_LIBS)
+ AC_SUBST(LIBTRANSLATE_CFLAGS)
+else
+PKG_CHECK_MODULES(LIBTRANSLATE, [libtranslate], [
+ HAVE_LIBTRANSLATE=yes
+],[
+ HAVE_LIBTRANSLATE=no
+])
+
+if test $HAVE_LIBTRANSLATE = yes; then
+ AC_DEFINE(HAVE_LIBTRANSLATE,1,[Defines if libtranslate is available])
+ AC_CHECK_LIB(translate, translate_session_timed_translate_text, [
+ HAVE_LIBTRANSLATE_TIMED_TRANSLATE=yes
+ AC_DEFINE(HAVE_LIBTRANSLATE_TIMED_TRANSLATE,1,[Defines if libtranslate has time limited translate])
+ ],[
+ HAVE_LIBTRANSLATE_TIMED_TRANSLATE=no
+ ])
+else
+ HAVE_LIBTRANSLATE_TIMED_TRANSLATE=no
+fi
+fi
dnl Checks for typedefs, structures, and compiler characteristics.
AC_C_CONST
@@ -164,7 +200,7 @@ AC_C_CONST
dnl Checks for library functions.
AC_CHECK_FUNCS(strcasecmp strncasecmp strdup strnlen)
-AC_OUTPUT(src/Makefile engines/Makefile ui/Makefile examples/Makefile Makefile librcc.spec)
+AC_OUTPUT(src/Makefile engines/Makefile external/Makefile ui/Makefile examples/Makefile Makefile librcc.spec)
echo ""
echo "Configuration:"
@@ -173,6 +209,8 @@ echo " Enca Charset Detection Support: $HAVE_ENCA"
echo " LibRCD Charset Detection Support: $HAVE_RCD"
echo ""
echo " Multilanguage support with DB4: $HAVE_BDB"
+echo " Libtranslate support: $HAVE_LIBTRANSLATE"
+echo " Libtranslate Timed Translate: $HAVE_LIBTRANSLATE_TIMED_TRANSLATE"
echo ""
echo "User Interfaces:"
echo " GTK User Interface: $HAVE_GTK"
diff --git a/examples/Makefile.am b/examples/Makefile.am
index 6886a77..99b7506 100644
--- a/examples/Makefile.am
+++ b/examples/Makefile.am
@@ -1,6 +1,8 @@
-bin_PROGRAMS= example
-example_SOURCES= example.c
-example_LDADD= ../src/librcc.la
+bin_PROGRAMS= example1 example2
+example1_SOURCES= example1.c
+example1_LDADD= ../src/librcc.la
+example2_SOURCES= example2.c
+example2_LDADD= ../src/librcc.la
if HAVE_GTK
bin_PROGRAMS+= rcc-gtk-config
@@ -18,7 +20,7 @@ endif
EXTRA_DIST= input-russian.txt rcc.xml rcc-example.xml mpg123-rcc.patch
-test-russian: example
- cat input-russian.txt | ./example
+test-russian: example2
+ cat input-russian.txt | ./example2 ru
AM_CPPFLAGS = -I../src -I../ui
diff --git a/examples/example.c b/examples/example1.c
index 43fc853..43fc853 100644
--- a/examples/example.c
+++ b/examples/example1.c
diff --git a/examples/example2.c b/examples/example2.c
new file mode 100644
index 0000000..cc4a3fa
--- /dev/null
+++ b/examples/example2.c
@@ -0,0 +1,60 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <locale.h>
+
+#include <librcc.h>
+
+
+int main(int argc, char *argv[]) {
+ rcc_language_id language_id, current_language_id, english_language_id;
+ rcc_string rccstring;
+ const char *language;
+ char buf[255];
+ char *recoded;
+
+ rcc_class classes[] = {
+ { "input", RCC_CLASS_STANDARD, NULL, NULL, "Input Encoding", 0 },
+ { "output", RCC_CLASS_STANDARD, "LC_CTYPE", NULL, "Output Encoding", 0 },
+ { NULL }
+ };
+
+ setlocale(LC_ALL, "");
+
+ rccInit();
+ rccInitDefaultContext(NULL, 0, 0, classes, 0);
+ rccInitDb4(NULL, "example", 0);
+ rccSetOption(NULL, RCC_OPTION_TRANSLATE, 1);
+
+// rccExternalInit();
+// rccExternalFree();
+
+ current_language_id = rccGetCurrentLanguage(NULL);
+ english_language_id = rccGetLanguageByName(NULL, "en");
+ if (argc>1) rccSetLanguageByName(NULL, argv[1]);
+ language_id = rccGetCurrentLanguage(NULL);
+
+ language = rccGetCurrentLanguageName(NULL);
+ if (language) printf("Current Language: %s\n\n", language);
+ else printf("Unable Detect Language\n\n");
+
+ while (fgets(buf,255,stdin)) {
+ if (strlen(buf)<2) break;
+
+ rccSetLanguage(NULL, language_id);
+ rccstring = rccFrom(NULL, 0, buf);
+ if (rccstring) {
+ rccSetLanguage(NULL, english_language_id);
+ recoded = rccTo(NULL, 1, rccstring);
+ if (recoded) {
+ printf(recoded);
+ free(recoded);
+ } else printf("Recoding from UTF-8 is failed\n");
+ free(rccstring);
+ } else printf("Recoding to UTF-8 is failed\n");
+ }
+
+ rccFree();
+
+ return 0;
+}
diff --git a/examples/rcc-gtk-config.c b/examples/rcc-gtk-config.c
index 7758f09..d0775a6 100644
--- a/examples/rcc-gtk-config.c
+++ b/examples/rcc-gtk-config.c
@@ -38,15 +38,15 @@ int main (int argc, char *argv[])
if (argc<1) config = argv[0];
else config = argv[1];
- gtk_set_locale ();
- gtk_init (&argc, &argv);
-
rccInit();
rccUiInit();
ctx = rccCreateContext(NULL, 0, 0, classes, 0);
rccLoad(ctx, config);
uictx = rccUiCreateContext(ctx);
+ gtk_set_locale ();
+ gtk_init (&argc, &argv);
+
window1 = gtk_window_new (GTK_WINDOW_TOPLEVEL);
gtk_window_set_policy(GTK_WINDOW (window1), FALSE, FALSE, TRUE);
gtk_window_set_title (GTK_WINDOW (window1), "LibRCC Config");
diff --git a/external/Makefile.am b/external/Makefile.am
new file mode 100644
index 0000000..68d2988
--- /dev/null
+++ b/external/Makefile.am
@@ -0,0 +1,12 @@
+if HAVE_GLIB2
+bin_PROGRAMS= rccexternal
+endif
+
+bindir = $(pkgdatadir)/
+
+rccexternal_SOURCES= rccexternal.c \
+ rcclibtranslate.c rcclibtranslate.h \
+ ../src/rccdb4.c ../src/rccdb4.h
+
+rccexternal_LDADD= @GLIB2_LIBS@ @LIBTRANSLATE_LIBS@ @BDB_LIBS@
+AM_CPPFLAGS = @GLIB2_CFLAGS@ @LIBTRANSLATE_CFLAGS@ @BDB_INCLUDES@ -I../src
diff --git a/external/rccexternal.c b/external/rccexternal.c
new file mode 100644
index 0000000..47f628a
--- /dev/null
+++ b/external/rccexternal.c
@@ -0,0 +1,117 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "../config.h"
+
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif /* HAVE_UNISTD_H */
+
+#ifdef HAVE_PWD_H
+# include <pwd.h>
+#endif /* HAVE_PWD_H */
+
+#ifdef HAVE_SYS_TYPES_H
+# include <sys/types.h>
+#endif /* HAVE_SYS_TYPES_H */
+#ifdef HAVE_SYS_SOCKET_H
+# include <sys/socket.h>
+#endif /* HAVE_SYS_SOCKET_H */
+#ifdef HAVE_SYS_STAT_H
+# include <sys/stat.h>
+#endif /* HAVE_SYS_STAT_H */
+#ifdef HAVE_SYS_UN_H
+# include <sys/un.h>
+#endif /* HAVE_SYS_UN_H */
+
+#include <glib/gthread.h>
+
+#include "../src/rccexternal.h"
+#include "rcclibtranslate.h"
+
+
+int main() {
+ int s, sd;
+ char addr[376];
+ const char *rcc_home_dir;
+ struct sockaddr_un mysock, clisock;
+ socklen_t socksize;
+ pid_t mypid;
+
+ unsigned char loopflag = 1;
+
+ rcc_external_info info;
+ ssize_t readed;
+ unsigned char cmd;
+
+#ifdef HAVE_PWD_H
+ struct passwd *pw;
+#endif /* HAVE_PWD_H */
+
+ mypid = getpid();
+
+ rcc_home_dir = getenv ("HOME");
+#ifdef HAVE_PWD_H
+ if (!rcc_home_dir) {
+ setpwent ();
+ pw = getpwuid(getuid ());
+ endpwent ();
+ if ((pw)&&(pw->pw_dir)) rcc_home_dir = pw->pw_dir;
+ }
+#endif /* HAVE_PWD_H */
+ if (strlen(rcc_home_dir)>256) return -1;
+ if (!rcc_home_dir) rcc_home_dir = "/";
+
+ rccLibTranslateInit(rcc_home_dir);
+
+ sprintf(addr,"%s/.rcc/comm/",rcc_home_dir);
+ mkdir(addr, 00600);
+ sprintf(addr,"%s/.rcc/comm/%lu.sock", rcc_home_dir, (unsigned long)mypid);
+
+ s = socket(PF_UNIX, SOCK_STREAM, 0);
+ if (!s) return -1;
+
+ memset(&mysock, 0, sizeof(mysock));
+ mysock.sun_family=AF_UNIX;
+ strncpy(mysock.sun_path,addr,sizeof(mysock.sun_path));
+ mysock.sun_path[sizeof(mysock.sun_path)-1]=0;
+
+ unlink(addr);
+ if (bind(s,(struct sockaddr*)&mysock,sizeof(mysock))==-1) return -1;
+ if (listen(s,1)<0) {
+ unlink(addr);
+ return -1;
+ }
+
+ while (loopflag) {
+ sd = accept(s,(struct sockaddr*)&clisock,&socksize);
+ if (sd < 0) continue;
+
+ readed = recv(sd,&cmd,1,0);
+ if (readed<=0) {
+ close(sd);
+ continue;
+ }
+
+ switch (cmd) {
+ case RCC_EXTERNAL_MODULE_CONTROL:
+ loopflag = 0;
+ break;
+ case RCC_EXTERNAL_MODULE_LIBRTRANSLATE:
+ info = (rcc_external_info)malloc(sizeof(rcc_external_info_s));
+ if (info) info->s = sd;
+ else break;
+ if (g_thread_create(rccLibTranslate, info, FALSE, NULL)) continue;
+ break;
+ }
+ close(sd);
+ }
+
+ close(s);
+ unlink(addr);
+
+ rccLibTranslateFree();
+
+ return 0;
+}
diff --git a/external/rcclibtranslate.c b/external/rcclibtranslate.c
new file mode 100644
index 0000000..56ce8a2
--- /dev/null
+++ b/external/rcclibtranslate.c
@@ -0,0 +1,286 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+
+#include "../config.h"
+
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif /* HAVE_UNISTD_H */
+#ifdef HAVE_SYS_TYPES_H
+# include <sys/types.h>
+#endif /* HAVE_SYS_TYPES_H */
+#ifdef HAVE_SYS_STAT_H
+# include <sys/stat.h>
+#endif /* HAVE_SYS_STAT_H */
+
+#ifdef HAVE_LIBTRANSLATE
+#include <translate.h>
+#endif /* HAVE_LIBTRANSLATE */
+
+#include "../src/rccexternal.h"
+#include "../src/rcctranslate.h"
+#include "../src/rccdb4.h"
+#include "rcclibtranslate.h"
+
+
+#ifdef HAVE_LIBTRANSLATE
+static TranslateSession *session = NULL;
+static db4_context db4ctx = NULL;
+
+static int exitflag = 0;
+static GMutex *mutex = NULL;
+static GCond *cond = NULL;
+static GQueue *queue = NULL;
+static GThread *thread = NULL;
+
+
+static char *rccCreateKey(const char *from, const char *to, const char *data, size_t *keysize) {
+ char *res;
+
+ *keysize = strlen(data) + 4;
+ res = (char*)malloc((*keysize+1)*sizeof(char));
+ if (res) sprintf(res,"%s%s%s",from,to,data);
+ return res;
+}
+
+static void *rccLibPostponed(void *info) {
+ char *result;
+ char *data;
+ char from[3];
+ char to[3];
+
+ from[2] = 0;
+ to[2] = 0;
+
+ g_mutex_lock(mutex);
+ while (!exitflag) {
+ data = (char*)g_queue_pop_head(queue);
+ if (data) {
+ g_mutex_unlock(mutex);
+
+ memcpy(from, data, 2);
+ memcpy(to, data + 2, 2);
+ result = translate_session_translate_text(session, data + 4, from, to, NULL, NULL, NULL);
+
+ if (result) {
+ rccDb4SetKey(db4ctx, data, strlen(data), result);
+ free(result);
+ }
+
+ free(data);
+ g_mutex_lock(mutex);
+ } else {
+ g_cond_wait(cond, mutex);
+ }
+ }
+ g_mutex_unlock(mutex);
+ return NULL;
+}
+
+#endif /* HAVE_LIBTRANSLATE */
+
+
+int rccLibTranslateInit(const char *rcc_home_dir) {
+#ifdef HAVE_LIBTRANSLATE
+ size_t size;
+ char *dbname;
+ GSList *list = NULL;
+
+ const char *http_proxy;
+
+ if (!translate_init(NULL)) return -1;
+
+ http_proxy = getenv("HTTP_PROXY");
+ if (!http_proxy) http_proxy = getenv("http_proxy");
+ translate_set_proxy(http_proxy);
+
+ list = translate_get_services();
+
+ session = translate_session_new(list);
+
+ g_slist_foreach(list, (GFunc) g_object_unref, NULL);
+ g_slist_free(list);
+
+
+ size = strlen(rcc_home_dir) + 32;
+ dbname = (char*)malloc(size*sizeof(char));
+ if (dbname) {
+ sprintf(dbname,"%s/.rcc/",rcc_home_dir);
+ mkdir(dbname, 00644);
+
+ sprintf(dbname,"%s/.rcc/libtranslate.db/",rcc_home_dir);
+ mkdir(dbname, 00644);
+
+ db4ctx = rccDb4CreateContext(dbname, 0);
+ free(dbname);
+ }
+ if (db4ctx) {
+ mutex = g_mutex_new();
+ cond = g_cond_new();
+ if ((mutex)&&(cond))
+ queue = g_queue_new();
+ if (queue)
+ thread = g_thread_create(rccLibPostponed, NULL, TRUE, NULL);
+ }
+#endif /* HAVE_LIBTRANSLATE */
+
+ return 0;
+}
+
+void rccLibTranslateFree() {
+#ifdef HAVE_LIBTRANSLATE
+ char *ptr;
+ if (session) {
+ if (thread) {
+ exitflag = 1;
+ g_cond_signal(cond);
+ g_thread_join(thread);
+ thread = NULL;
+ exitflag = 0;
+ }
+ if (queue) {
+ do {
+ ptr = g_queue_pop_head(queue);
+ if (ptr) free(ptr);
+ } while (ptr);
+ g_queue_free(queue);
+ queue = NULL;
+ }
+ if (mutex) {
+ g_mutex_free(mutex);
+ mutex = NULL;
+ }
+ if (cond) {
+ g_cond_free(cond);
+ cond = NULL;
+ }
+ if (db4ctx) rccDb4FreeContext(db4ctx);
+ g_object_unref(session);
+ session = NULL;
+ }
+#endif /* HAVE_LIBTRANSLATE */
+}
+
+
+static char *rccLibTranslateDo(const char *from, const char *to, const char *text, unsigned long timeout) {
+#ifdef HAVE_LIBTRANSLATE
+ char *result;
+ char *key = NULL;
+ size_t keysize;
+
+ if ((!session)||(!from)||(!to)||(!text)) return NULL;
+ if ((strlen(from)!=2)||(strlen(to)!=2)) return NULL;
+
+ if (db4ctx) {
+ key = rccCreateKey(from,to,text,&keysize);
+ if (key) {
+ result = rccDb4GetKey(db4ctx, key, keysize);
+ if (result) {
+ free(key);
+ return result;
+ }
+ }
+ }
+# ifdef HAVE_LIBTRANSLATE_TIMED_TRANSLATE
+ result = translate_session_timed_translate_text(session, text, from, to, timeout, NULL, NULL, NULL);
+# else
+ result = translate_session_translate_text(session, text, from, to, NULL, NULL, NULL);
+# endif /* HAVE_LIBTRANSLATE_TIMED_TRANSLATE */
+
+ if ((db4ctx)&&(key)) {
+ if (result) {
+ rccDb4SetKey(db4ctx, key, keysize, result);
+ free(key);
+ }
+ else {
+ g_mutex_lock(mutex);
+ g_queue_push_tail(queue, key);
+ g_mutex_unlock(mutex);
+ g_cond_signal(cond);
+ }
+ }
+
+ return result;
+#else
+ return NULL;
+#endif /* HAVE_LIBTRANSLATE */
+}
+
+
+void *rccLibTranslate(void *info) {
+ int s;
+#ifdef HAVE_LIBTRANSLATE
+ unsigned char connected = 1;
+ rcc_translate_prefix_s prefix;
+ ssize_t readed, writed, res;
+ char *buffer;
+ size_t size;
+ char *translated = NULL;
+#endif /* HAVE_LIBTRANSLATE */
+
+ if (!info) return NULL;
+
+ s = ((rcc_external_info)info)->s;
+ free(info);
+
+#ifdef HAVE_LIBTRANSLATE
+ while (connected) {
+ readed = read(s, &prefix, sizeof(rcc_translate_prefix_s)-1);
+ if ((readed<=0)||(readed != (sizeof(rcc_translate_prefix_s)-1))) break;
+
+ switch (prefix.cmd.cmd) {
+ case RCC_EXTERNAL_COMMAND_CLOSE:
+ connected = 0;
+ break;
+ case RCC_EXTERNAL_COMMAND_TRANSLATE:
+ size = 1 + prefix.cmd.size + sizeof(rcc_external_command_s) - sizeof(rcc_translate_prefix_s);
+ buffer = (char*)malloc(size);
+ if (buffer) {
+ for (readed = 0; (readed < size)&&(connected); readed += res) {
+ res = read(s, buffer + readed, size - readed);
+ if (res<=0) connected = 0;
+ }
+
+ prefix.cmd.cmd = 0;
+ prefix.cmd.size = 0;
+
+ if ((prefix.from[2])||(prefix.to[2])||(buffer[readed-1])) goto respond;
+
+ translated = rccLibTranslateDo(prefix.from, prefix.to, buffer, prefix.timeout);
+ if (translated) {
+ prefix.cmd.cmd = RCC_EXTERNAL_COMMAND_TRANSLATE;
+ prefix.cmd.size = strlen(translated) + 1;
+ }
+
+respond:
+ res = write(s, &prefix.cmd, sizeof(rcc_external_command_s));
+ if (res == sizeof(rcc_external_command_s)) {
+ for (writed = 0; (writed < prefix.cmd.size)&&(connected); writed += res) {
+ res = write(s, translated + writed, prefix.cmd.size - writed);
+ if (res<=0) connected = 0;
+ }
+ } else connected = 0;
+
+ if (prefix.cmd.size) free(translated);
+ free(buffer);
+ } else connected = 0;
+ break;
+ default:
+ buffer = (char*)malloc(prefix.cmd.size);
+ if (buffer) {
+ for (readed = 0; (readed < prefix.cmd.size)&&(connected); readed += res) {
+ res = read(s, buffer + readed, prefix.cmd.size - readed);
+ if (res<=0) connected = 0;
+ }
+ free(buffer);
+ } else connected = 0;
+ }
+ }
+#endif /* HAVE_LIBTRANSLATE */
+
+ close(s);
+ return NULL;
+}
+
diff --git a/external/rcclibtranslate.h b/external/rcclibtranslate.h
new file mode 100644
index 0000000..f54f5e6
--- /dev/null
+++ b/external/rcclibtranslate.h
@@ -0,0 +1,9 @@
+#ifndef _RCC_LIBTRANSLATE_H
+#define _RCC_LIBTRANSLATE_H
+
+int rccLibTranslateInit(const char *rcc_home_dir);
+void rccLibTranslateFree();
+
+void *rccLibTranslate(void *info);
+
+#endif /* _RCC_LIBTRANSLATE_H */
diff --git a/src/Makefile.am b/src/Makefile.am
index 50c6836..baa08a4 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -8,6 +8,7 @@ librcc_la_SOURCES = librcc.c \
rccconfig.c rccconfig.h \
rcclist.c rcclist.h \
plugin.c plugin.h \
+ rccexternal.c rccexternal.h \
fake_enca.h fake_rcd.h \
rccenca.c rccenca.h \
rccdb4.c rccdb4.h \
@@ -15,6 +16,7 @@ librcc_la_SOURCES = librcc.c \
rccstring.c rccstring.h \
rccxml.c rccxml.h \
rcciconv.c rcciconv.h \
+ rcctranslate.c rcctranslate.h \
fs.c fs.h \
recode.c recode.h \
internal.h
diff --git a/src/fs.c b/src/fs.c
index c378704..fb0a2bc 100644
--- a/src/fs.c
+++ b/src/fs.c
@@ -195,7 +195,7 @@ const char *rccFS2(rcc_language_config config, iconv_t icnv, const char *prefix,
char *tmpbuffer = config->ctx->tmpbuffer;
if (icnv) {
- size = rccIConv(config->ctx, icnv, name, 0);
+ size = rccIConvInternal(config->ctx, icnv, name, 0);
if (size == (size_t)-1) return NULL;
} else {
strncpy(tmpbuffer, name, RCC_MAX_STRING_CHARS);
diff --git a/src/librcc.c b/src/librcc.c
index ec2df39..c0112df 100644
--- a/src/librcc.c
+++ b/src/librcc.c
@@ -11,6 +11,9 @@
#ifdef HAVE_SYS_TYPES_H
# include <sys/types.h>
#endif /* HAVE_SYS_TYPES_H */
+#ifdef HAVE_SYS_STAT_H
+# include <sys/stat.h>
+#endif /* HAVE_SYS_STAT_H */
#ifdef HAVE_PWD_H
# include <pwd.h>
@@ -23,6 +26,8 @@
#include "plugin.h"
#include "engine.h"
#include "rccxml.h"
+#include "rccexternal.h"
+#include "rcctranslate.h"
static int initialized = 0;
char *rcc_home_dir = NULL;
@@ -43,6 +48,9 @@ rcc_compiled_configuration rccGetCompiledConfiguration() {
#ifdef HAVE_DB_H
compiled_configuration.flags|=RCC_CC_FLAG_HAVE_BERKLEY_DB;
#endif /* HAVE_DB_H */
+#ifdef HAVE_LIBTRANSLATE
+ compiled_configuration.flags|=RCC_CC_FLAG_HAVE_LIBTRANSLATE;
+#endif /* HAVE_LIBTRANSLATE */
return &compiled_configuration;
}
@@ -72,7 +80,12 @@ int rccInit() {
memcpy(rcc_default_languages, rcc_default_languages_embeded, (RCC_MAX_LANGUAGES + 1)*sizeof(rcc_language));
memcpy(rcc_option_descriptions, rcc_option_descriptions_embeded, (RCC_MAX_OPTIONS + 1)*sizeof(rcc_option_description));
+#ifdef HAVE_LIBTRANSLATE
+ rccExternalInit();
+#endif /* HAVE_LIBTRANSLATE */
+
err = rccPluginInit();
+ if (!err) err = rccTranslateInit();
if (!err) err = rccXmlInit(1);
if (!err) err = rccEngineInit();
@@ -94,8 +107,11 @@ void rccFree() {
rccEngineFree();
rccXmlFree();
+ rccTranslateFree();
rccPluginFree();
+ rccExternalFree();
+
if (rcc_home_dir) {
free(rcc_home_dir);
rcc_home_dir = NULL;
@@ -274,6 +290,35 @@ void rccFreeContext(rcc_context ctx) {
}
}
+int rccInitDb4(rcc_context ctx, const char *name, rcc_db4_flags flags) {
+ size_t size;
+ char *dbname;
+
+ if (!ctx) {
+ if (rcc_default_ctx) ctx = rcc_default_ctx;
+ else return -1;
+ }
+
+ if (!name) name = "default";
+
+ size = strlen(rcc_home_dir) + strlen(name) + 32;
+ dbname = (char*)malloc(size*sizeof(char));
+ if (!dbname) return -1;
+
+ sprintf(dbname,"%s/.rcc/",rcc_home_dir);
+ mkdir(dbname, 00644);
+
+ sprintf(dbname,"%s/.rcc/%s.db/",rcc_home_dir,name);
+ mkdir(dbname, 00644);
+
+ ctx->db4ctx = rccDb4CreateContext(dbname, flags);
+ free(dbname);
+
+ if (!ctx->db4ctx) return -1;
+
+ return 0;
+}
+
int rccLockConfiguration(rcc_context ctx, unsigned int lock_code) {
if (!ctx) {
if (rcc_default_ctx) ctx = rcc_default_ctx;
diff --git a/src/librcc.h b/src/librcc.h
index a70d6df..52e6be4 100644
--- a/src/librcc.h
+++ b/src/librcc.h
@@ -371,6 +371,8 @@ typedef enum rcc_option_t {
RCC_OPTION_AUTODETECT_FS_TITLES, /**< Detect titles of #RCC_CLASS_FS classes */
RCC_OPTION_AUTODETECT_FS_NAMES, /**< Try to find encoding of #RCC_CLASS_FS by accessing fs */
RCC_OPTION_CONFIGURED_LANGUAGES_ONLY, /**< Use only configured languages or languages with auto-engines */
+ RCC_OPTION_TRANSLATE, /**< Translate #rcc_string if it's language differs from current one */
+ RCC_OPTION_AUTOENGINE_SET_CURRENT, /**< If enabled autodetection engine will set current charset */
RCC_MAX_OPTIONS
} rcc_option;
@@ -908,7 +910,6 @@ typedef struct rcc_iconv_t *rcc_iconv;
* @result
* - NULL if no recoding is required
* - Pointer on initialized context if successful
- * - Pointer on errnous context in the case of error
*/
rcc_iconv rccIConvOpen(const char *from, const char *to);
/**
@@ -920,13 +921,53 @@ void rccIConvClose(rcc_iconv icnv);
* Recodes chunk of data.
*
* @param icnv is recoding context
- * @param outbuf is preallocated output buffer
- * @param outsize is size of output buffer (striped string will be returned if buffer to small)
* @param buf is data for recoding
- * @param size is size of the data
- * @return number of recoded bytes in output buffer or -1 in the case of error
+ * @param len is size of the data
+ * @param rlen is size of recoded data
+ * @return recoded string or NULL in the case of error
*/
-size_t rccIConvRecode(rcc_iconv icnv, char *outbuf, size_t outsize, const char *buf, size_t size);
+char *rccIConv(rcc_iconv icnv, const char *buf, size_t len, size_t *rlen);
+
+/**
+ * translating context
+ */
+typedef struct rcc_translate_t *rcc_translate;
+
+/* rcctranslate.c */
+/**
+ * Open translating context.
+ *
+ * @param from is source language
+ * @param to is destination language
+ * @return
+ * - NULL if translation is not required or possible
+ * - Pointer on initialized context if successful
+ */
+rcc_translate rccTranslateOpen(const char *from, const char *to);
+/**
+ * Close translating context.
+ *
+ * @param translate is translating context
+ */
+void rccTranslateClose(rcc_translate translate);
+
+/*
+ * Set translation timeout
+ *
+ * @param translate is translating context
+ * @param us is timeout in microseconds (0 - no timeout)
+ * @return non-zero value is returned in the case of errror
+ */
+int rccTranslateSetTimeout(rcc_translate translate, unsigned long us);
+
+/**
+ * Translate string.
+ *
+ * @param translate is translating context
+ * @param buf is UTF-8 encoded string for translating
+ * @return recoded string or NULL in the case of error
+ */
+char *rccTranslate(rcc_translate translate, const char *buf);
/* recode.c */
/**
@@ -1119,6 +1160,11 @@ rcc_context rccEngineGetRccContext(rcc_engine_context ctx);
*/
#define RCC_CC_FLAG_HAVE_RCD 0x08
/**
+ * Libtranslate translation engine compiled in
+ */
+#define RCC_CC_FLAG_HAVE_LIBTRANSLATE 0x10
+
+/**
* The library build environment is represented by this structure
*/
struct rcc_compiled_configuration_t {
diff --git a/src/lngconfig.c b/src/lngconfig.c
index efb2c1a..c50ee74 100644
--- a/src/lngconfig.c
+++ b/src/lngconfig.c
@@ -164,6 +164,7 @@ int rccConfigInit(rcc_language_config config, rcc_context ctx) {
}
config->fsiconv = NULL;
+ config->trans = NULL;
config->ctx = ctx;
config->language = NULL;
@@ -199,6 +200,10 @@ void rccConfigFreeIConv(rcc_language_config config) {
void rccConfigClear(rcc_language_config config) {
if ((config)&&(config->charset)) {
rccConfigFreeIConv(config);
+ if (config->trans) {
+ rccTranslateClose(config->trans);
+ config->trans = NULL;
+ }
if (config->iconv_to) {
free(config->iconv_to);
config->iconv_to = NULL;
@@ -521,7 +526,7 @@ int rccConfigConfigure(rcc_language_config config) {
if ((!charset)||(rccIsUTF8(charset))) continue;
config->iconv_to[i] = rccIConvOpen(charset, "UTF-8");
}
-
+
config->configure = 0;
return 0;
diff --git a/src/lngconfig.h b/src/lngconfig.h
index b136905..92cc050 100644
--- a/src/lngconfig.h
+++ b/src/lngconfig.h
@@ -2,6 +2,7 @@
#define _RCC_LNGCONFIG_H
#include "rcciconv.h"
+#include "rcctranslate.h"
struct rcc_language_config_t {
rcc_context ctx;
@@ -16,6 +17,9 @@ struct rcc_language_config_t {
unsigned char configured;
+ rcc_translate trans;
+ rcc_language_id translang;
+
rcc_iconv fsiconv;
};
typedef struct rcc_language_config_t rcc_language_config_s;
diff --git a/src/rccconfig.c b/src/rccconfig.c
index 57d38c3..ed6d30a 100644
--- a/src/rccconfig.c
+++ b/src/rccconfig.c
@@ -40,6 +40,10 @@ rcc_language rcc_default_languages_embeded[RCC_MAX_LANGUAGES + 1] = {
&rcc_default_engine,
NULL
}},
+{"en", {rcc_default_charset, rcc_utf8_charset, NULL}, {
+ &rcc_default_engine,
+ NULL
+}},
{"ru", {rcc_default_charset,"KOI8-R","CP1251",rcc_utf8_charset,"IBM866","MACCYRILLIC","ISO8859-5", NULL}, {
&rcc_default_engine,
#ifdef RCC_RCD_SUPPORT
@@ -115,6 +119,8 @@ rcc_option_description rcc_option_descriptions_embeded[RCC_MAX_OPTIONS+1] = {
{RCC_OPTION_AUTODETECT_FS_NAMES, 1, { RCC_OPTION_RANGE_TYPE_BOOLEAN, 0, 0, 0}, RCC_OPTION_TYPE_STANDARD, "AUTODETECT_FS_NAMES", rcc_sn_boolean},
{RCC_OPTION_AUTODETECT_FS_TITLES, 1, { RCC_OPTION_RANGE_TYPE_BOOLEAN, 0, 0, 0}, RCC_OPTION_TYPE_INVISIBLE, "AUTODETECT_FS_TITLES", rcc_sn_boolean},
{RCC_OPTION_CONFIGURED_LANGUAGES_ONLY, 1, { RCC_OPTION_RANGE_TYPE_MENU, 0, 2, 1}, RCC_OPTION_TYPE_INVISIBLE, "CONFIGURED_LANGUAGES_ONLY", rcc_sn_clo},
+ {RCC_OPTION_TRANSLATE, 0, { RCC_OPTION_RANGE_TYPE_BOOLEAN, 0, 0, 0}, RCC_OPTION_TYPE_STANDARD, "TRANSLATE", rcc_sn_boolean },
+ {RCC_OPTION_AUTOENGINE_SET_CURRENT, 0, { RCC_OPTION_RANGE_TYPE_BOOLEAN, 0, 0, 0}, RCC_OPTION_TYPE_STANDARD, "AUTOENGINE_SET_CURRENT", rcc_sn_boolean },
{RCC_MAX_OPTIONS}
};
diff --git a/src/rccdb4.c b/src/rccdb4.c
index d3e8cab..9c21477 100644
--- a/src/rccdb4.c
+++ b/src/rccdb4.c
@@ -4,48 +4,11 @@
#include "../config.h"
-#ifdef HAVE_SYS_TYPES_H
-# include <sys/types.h>
-#endif /* HAVE_SYS_TYPES_H */
-
-#ifdef HAVE_SYS_STAT_H
-# include <sys/stat.h>
-#endif /* HAVE_SYS_STAT_H */
-
#include "internal.h"
#include "rccdb4.h"
#define DATABASE "autolearn.db"
-int rccInitDb4(rcc_context ctx, const char *name, rcc_db4_flags flags) {
- size_t size;
- char *dbname;
-
- if (!ctx) {
- if (rcc_default_ctx) ctx = rcc_default_ctx;
- else return -1;
- }
-
- if (!name) name = "default";
-
- size = strlen(rcc_home_dir) + strlen(name) + 32;
- dbname = (char*)malloc(size*sizeof(char));
- if (!dbname) return -1;
-
- sprintf(dbname,"%s/.rcc/",rcc_home_dir);
- mkdir(dbname, 00644);
-
- sprintf(dbname,"%s/.rcc/%s.db/",rcc_home_dir,name);
- mkdir(dbname, 00644);
-
- ctx->db4ctx = rccDb4CreateContext(dbname, flags);
- free(dbname);
-
- if (!ctx->db4ctx) return -1;
-
- return 0;
-}
-
db4_context rccDb4CreateContext(const char *dbpath, rcc_db4_flags flags) {
int err;
db4_context ctx;
@@ -124,7 +87,7 @@ static void rccDb4Strip(DBT *key) {
}
#endif /* HAVE_DB_H */
-int rccDb4SetKey(db4_context ctx, const char *orig, size_t olen, const rcc_string string) {
+int rccDb4SetKey(db4_context ctx, const char *orig, size_t olen, const char *string) {
#ifdef HAVE_DB_H
DBT key, data;
#endif /* HAVE_DB_H */
@@ -149,7 +112,7 @@ int rccDb4SetKey(db4_context ctx, const char *orig, size_t olen, const rcc_strin
return 1;
}
-rcc_string rccDb4GetKey(db4_context ctx, const char *orig, size_t olen) {
+char *rccDb4GetKey(db4_context ctx, const char *orig, size_t olen) {
#ifdef HAVE_DB_H
DBT key, data;
#endif /* HAVE_DB_H */
diff --git a/src/rccdb4.h b/src/rccdb4.h
index 1d5072b..a11e53d 100644
--- a/src/rccdb4.h
+++ b/src/rccdb4.h
@@ -3,12 +3,12 @@
#include "../config.h"
+#include "librcc.h"
+
#ifdef HAVE_DB_H
# include <db.h>
#endif /* HAVE_DB_H */
-#include "rccstring.h"
-
struct db4_context_t {
#ifdef HAVE_DB_H
DB_ENV *dbe;
@@ -24,7 +24,7 @@ typedef struct db4_context_t *db4_context;
db4_context rccDb4CreateContext(const char *dbpath, rcc_db4_flags flags);
void rccDb4FreeContext(db4_context ctx);
-int rccDb4SetKey(db4_context ctx, const char *orig, size_t olen, const rcc_string string);
-rcc_string rccDb4GetKey(db4_context ctx, const char *orig, size_t olen);
+int rccDb4SetKey(db4_context ctx, const char *orig, size_t olen, const char *string);
+char *rccDb4GetKey(db4_context ctx, const char *orig, size_t olen);
#endif /* _RCC_DB4_H */
diff --git a/src/rccexternal.c b/src/rccexternal.c
new file mode 100644
index 0000000..16b3667
--- /dev/null
+++ b/src/rccexternal.c
@@ -0,0 +1,210 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <errno.h>
+
+#include "../config.h"
+
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif /* HAVE_UNISTD_H */
+#ifdef HAVE_FCNTL_H
+# include <fcntl.h>
+#endif /* HAVE_FCNTL_H */
+#ifdef HAVE_SIGNAL_H
+# include <signal.h>
+#endif /* HAVE_SIGNAL_H */
+
+#ifdef HAVE_SYS_TYPES_H
+# include <sys/types.h>
+#endif /* HAVE_SYS_TYPES_H */
+#ifdef HAVE_SYS_SOCKET_H
+# include <sys/socket.h>
+#endif /* HAVE_SYS_SOCKET_H */
+#ifdef HAVE_SYS_STAT_H
+# include <sys/stat.h>
+#endif /* HAVE_SYS_STAT_H */
+#ifdef HAVE_SYS_UN_H
+# include <sys/un.h>
+#endif /* HAVE_SYS_UN_H */
+#ifdef HAVE_SYS_TIME_H
+# include <sys/time.h>
+#endif /* HAVE_SYS_TIME_H */
+#ifdef HAVE_SYS_SELECT_H
+# include <sys/select.h>
+#endif /* HAVE_SYS_SELECT_H */
+#ifdef HAVE_SYS_WAIT_H
+# include <sys/wait.h>
+#endif /* HAVE_SYS_WAIT_H */
+
+#include "rccexternal.h"
+#include "internal.h"
+
+#define RCC_EXT_PROG_NAME "rccexternal"
+
+static pid_t pid = (pid_t)-1;
+static char *addr = NULL;
+
+int rccExternalInit() {
+#ifdef HAVE_SIGNAL_H
+ struct sigaction act;
+#endif /* HAVE_SIGNAL_H */
+
+ if (pid != (pid_t)-1) return 0;
+
+ if (!addr) {
+ addr = (char*)malloc(strlen(rcc_home_dir)+32);
+ if (!addr) return -1;
+ }
+
+ pid = fork();
+ if (pid) {
+ if (pid == (pid_t)-1) return -1;
+ sprintf(addr,"%s/.rcc/comm/%lu.sock", rcc_home_dir, (unsigned long)pid);
+
+#ifdef HAVE_SIGNAL_H
+ act.sa_handler = SIG_IGN;
+ sigemptyset(&act.sa_mask);
+ act.sa_flags = 0;
+ sigaction(SIGPIPE,&act,NULL);
+#endif /* HAVE_SIGNAL_H */
+
+ return 0;
+ }
+
+ execl(LIBRCC_DATA_DIR "/" RCC_EXT_PROG_NAME, RCC_EXT_PROG_NAME, NULL);
+ exit(1);
+}
+
+void rccExternalFree() {
+ if (pid == (pid_t)-1) return;
+
+ rccExternalConnect(0);
+ if (addr) free(addr);
+
+ waitpid(pid, NULL, 0);
+ pid = (pid_t)-1;
+}
+
+static int rccExternalSetDeadline(struct timeval *tv, unsigned long timeout) {
+ gettimeofday(tv, NULL);
+ tv->tv_sec += (tv->tv_usec + timeout + RCC_EXTERNAL_TIMEOUT) / 1000000;
+ tv->tv_usec = (tv->tv_usec + timeout + RCC_EXTERNAL_TIMEOUT) % 1000000;
+ return 0;
+}
+
+size_t rccExternalWrite(int s, const char *buffer, ssize_t size, unsigned long timeout) {
+ int err;
+ unsigned char connected = 1;
+ ssize_t writed, res = 0;
+ struct timeval tv;
+ fd_set fdcon;
+
+ if (s == -1) return -1;
+
+ for (writed = 0; (writed < size)&&(connected); writed += connected?res:0) {
+ FD_ZERO(&fdcon);
+ FD_SET(s, &fdcon);
+ rccExternalSetDeadline(&tv, timeout);
+ err = select(s+1,NULL,&fdcon,NULL,&tv);
+ if (err<=0) connected = 0;
+ else {
+ res = write(s, buffer + writed, size - writed);
+ if (res<=0) connected = 0;
+ }
+ }
+
+ return size - writed;
+}
+
+size_t rccExternalRead(int s, char *buffer, ssize_t size, unsigned long timeout) {
+ int err;
+ unsigned char connected = 1;
+ ssize_t readed, res = 0;
+ struct timeval tv;
+ fd_set fdcon;
+
+ if (s == -1) return -1;
+
+ for (readed = 0; (readed < size)&&(connected); readed += connected?res:0) {
+ FD_ZERO(&fdcon);
+ FD_SET(s, &fdcon);
+ rccExternalSetDeadline(&tv, timeout);
+ err = select(s+1,&fdcon,NULL,NULL,&tv);
+ if (err<=0) connected = 0;
+ else {
+ res = read(s, buffer + readed, size - readed);
+ if (res<=0) connected = 0;
+ }
+ }
+
+ return size - readed;
+}
+
+int rccExternalConnect(unsigned char module) {
+ int err;
+ int retries = 10;
+ int sock;
+ int flags;
+ struct sockaddr_un mysock;
+ struct timeval tv;
+ struct timespec ts;
+ fd_set fdcon;
+
+ if (pid == (pid_t)-1) return -1;
+
+ sock = socket(PF_UNIX, SOCK_STREAM, 0);
+ if (sock<=0) return -1;
+
+ flags = fcntl(sock,F_GETFL,0);
+ if (flags<0) flags = 0;
+ if (fcntl(sock,F_SETFL,flags|O_NONBLOCK)<0) {
+ close(sock);
+ return -1;
+ }
+
+ memset(&mysock, 0, sizeof(mysock));
+ mysock.sun_family=AF_UNIX;
+ strncpy(mysock.sun_path,addr,sizeof(mysock.sun_path));
+ mysock.sun_path[sizeof(mysock.sun_path)-1]=0;
+
+again:
+ if (connect(sock,(struct sockaddr*)&mysock,sizeof(mysock))<0) {
+ if (errno == EINPROGRESS) {
+ FD_ZERO(&fdcon);
+ FD_SET(sock, &fdcon);
+
+ rccExternalSetDeadline(&tv, 0);
+ err = select(sock+1,&fdcon,NULL,NULL,&tv);
+ if (err<=0) {
+ close(sock);
+ return -1;
+ }
+ } else if ((errno == ENOENT)&&(retries)) {
+ ts.tv_sec = (RCC_EXTERNAL_TIMEOUT/10) / 1000000;
+ ts.tv_nsec = ((RCC_EXTERNAL_TIMEOUT/10) % 1000000)*1000;
+ nanosleep(&ts, NULL);
+ retries--;
+ goto again;
+ } else {
+ close(sock);
+ return -1;
+ }
+ }
+
+ if (rccExternalWrite(sock, &module, 1, 0)) {
+ close(sock);
+ return -1;
+ }
+
+ return sock;
+}
+
+void rccExternalClose(int s) {
+ unsigned char cmd = 0;
+ if (s != -1) {
+ write(s, &cmd, 1);
+ close(s);
+ }
+}
diff --git a/src/rccexternal.h b/src/rccexternal.h
new file mode 100644
index 0000000..bffd6b3
--- /dev/null
+++ b/src/rccexternal.h
@@ -0,0 +1,35 @@
+#ifndef _RCC_EXTERNAL_H
+#define _RCC_EXTERNAL_H
+
+#define RCC_EXTERNAL_TIMEOUT 1000000
+
+typedef enum rcc_external_module_t {
+ RCC_EXTERNAL_MODULE_CONTROL = 0,
+ RCC_EXTERNAL_MODULE_LIBRTRANSLATE,
+ RCC_EXTERNAL_MODULE_MAX
+} rcc_external_module;
+
+struct rcc_external_info_t {
+ int s;
+};
+typedef struct rcc_external_info_t rcc_external_info_s;
+typedef struct rcc_external_info_t *rcc_external_info;
+
+struct rcc_external_command_t {
+ unsigned long size;
+ unsigned char cmd;
+};
+typedef struct rcc_external_command_t rcc_external_command_s;
+typedef struct rcc_external_command_t *rcc_external_command;
+
+#define RCC_EXTERNAL_COMMAND_CLOSE 0
+
+int rccExternalInit();
+void rccExternalFree();
+
+size_t rccExternalWrite(int s, const char *buffer, ssize_t size, unsigned long timeout);
+size_t rccExternalRead(int s, char *buffer, ssize_t size, unsigned long timeout);
+int rccExternalConnect(unsigned char module);
+void rccExternalClose(int s);
+
+#endif /* _RCC_EXTERNAL_H */
diff --git a/src/rcciconv.c b/src/rcciconv.c
index 65b32b3..d9903de 100644
--- a/src/rcciconv.c
+++ b/src/rcciconv.c
@@ -92,7 +92,28 @@ loop:
return outsize - out_left;
}
-size_t rccIConv(rcc_context ctx, rcc_iconv icnv, const char *buf, size_t len) {
+char *rccIConv(rcc_iconv icnv, const char *buf, size_t len, size_t *rlen) {
+ char *res;
+ size_t size;
+ char tmpbuffer[RCC_MAX_STRING_CHARS+1];
+
+ size = rccIConvRecode(icnv, tmpbuffer, RCC_MAX_STRING_CHARS, buf, len);
+ if (size != (size_t)-1) {
+ res = (char*)malloc((size+1)*sizeof(char));
+ if (!res) return res;
+
+ if (rlen) *rlen = size;
+ memcpy(res, tmpbuffer, size);
+ res[size] = 0;
+
+ return res;
+ }
+
+ return NULL;
+}
+
+size_t rccIConvInternal(rcc_context ctx, rcc_iconv icnv, const char *buf, size_t len) {
if (!ctx) return (size_t)-1;
return rccIConvRecode(icnv, ctx->tmpbuffer, RCC_MAX_STRING_CHARS, buf, len);
}
+
diff --git a/src/rcciconv.h b/src/rcciconv.h
index cc1d1b9..0070696 100644
--- a/src/rcciconv.h
+++ b/src/rcciconv.h
@@ -8,6 +8,18 @@ struct rcc_iconv_t {
};
typedef struct rcc_iconv_t rcc_iconv_s;
-size_t rccIConv(rcc_context ctx, rcc_iconv icnv, const char *buf, size_t len);
+size_t rccIConvInternal(rcc_context ctx, rcc_iconv icnv, const char *buf, size_t len);
+
+/**
+ * Recodes chunk of data.
+ *
+ * @param icnv is recoding context
+ * @param outbuf is preallocated output buffer
+ * @param outsize is size of output buffer (striped string will be returned if buffer to small)
+ * @param buf is data for recoding
+ * @param size is size of the data
+ * @return number of recoded bytes in output buffer or -1 in the case of error
+ */
+size_t rccIConvRecode(rcc_iconv icnv, char *outbuf, size_t outsize, const char *buf, size_t size);
#endif /* _RCC_ICONV_H */
diff --git a/src/rcctranslate.c b/src/rcctranslate.c
new file mode 100644
index 0000000..3bbd916
--- /dev/null
+++ b/src/rcctranslate.c
@@ -0,0 +1,151 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "internal.h"
+#include "rccexternal.h"
+#include "rcctranslate.h"
+
+
+
+int rccTranslateInit() {
+
+ return 0;
+}
+
+void rccTranslateFree() {
+}
+
+
+rcc_translate rccTranslateOpen(const char *from, const char *to) {
+#ifdef HAVE_LIBTRANSLATE
+ rcc_translate translate;
+
+ if ((!from)||(!to)||(!strcasecmp(from,to))) return NULL;
+ if ((strlen(from)!=2)||(strlen(to)!=2)) return NULL;
+
+ translate = (rcc_translate)malloc(sizeof(rcc_translate_s));
+ if (!translate) return NULL;
+
+ translate->sock = rccExternalConnect(RCC_EXTERNAL_MODULE_LIBRTRANSLATE);
+ if (translate->sock == -1) {
+ free(translate);
+ return NULL;
+ }
+
+ translate->remaining = 0;
+ translate->prefix.cmd.cmd = RCC_EXTERNAL_COMMAND_TRANSLATE;
+ translate->prefix.cmd.size = sizeof(rcc_translate_prefix_s);
+ memcpy(translate->prefix.from, from, 3*sizeof(char));
+ memcpy(translate->prefix.to, to, 3*sizeof(char));
+ rccTranslateSetTimeout(translate, RCC_TRANSLATE_DEFAULT_TIMEOUT);
+
+ return translate;
+#else
+ return NULL;
+#endif /* HAVE_LIBTRANSLATE */
+}
+
+void rccTranslateClose(rcc_translate translate) {
+#ifdef HAVE_LIBTRANSLATE
+ if (!translate) return;
+ if (translate->sock != -1) rccExternalClose(translate->sock);
+ free(translate);
+#endif /* HAVE_LIBTRANSLATE */
+}
+
+int rccTranslateSetTimeout(rcc_translate translate, unsigned long us) {
+#ifdef HAVE_LIBTRANSLATE_TIMED_TRANSLATE
+ if (!translate) return -1;
+ translate->prefix.timeout = us;
+ return 0;
+#else
+ return -1;
+#endif /* HAVE_LIBTRANSLATE_TIMED_TRANSLATE */
+}
+
+char *rccTranslate(rcc_translate translate, const char *buf) {
+#ifdef HAVE_LIBTRANSLATE
+ size_t i;
+ rcc_external_command_s resp;
+ size_t err, len;
+ char *buffer;
+
+ if ((!translate)||(!buf)) return NULL;
+
+ if (!strcmp(translate->prefix.to, "en")) {
+ for (i=0;buf[i];i++)
+ if ((unsigned char)buf[i]>0x7F) break;
+ if (!buf[i]) return NULL;
+ }
+
+ if (translate->sock == -1) {
+ translate->sock = rccExternalConnect(RCC_EXTERNAL_MODULE_LIBRTRANSLATE);
+ if (translate->sock == -1) return NULL;
+ } else if (translate->remaining) {
+ if (translate->remaining == (size_t)-1) {
+ err = rccExternalRead(translate->sock, (char*)&resp, sizeof(rcc_external_command_s), 0);
+ if (err) return NULL;
+ translate->remaining = resp.size;
+ }
+
+ buffer = (char*)malloc(translate->remaining*sizeof(char));
+ if (!buffer) {
+ rccExternalClose(translate->sock);
+ translate->sock = -1;
+ return NULL;
+ }
+ err = rccExternalRead(translate->sock, buffer, translate->remaining, 0);
+ free(buffer);
+ if (err) {
+ translate->remaining = err;
+ return NULL;
+ }
+ translate->remaining = 0;
+ }
+
+ len = strlen(buf);
+ translate->prefix.cmd.size = sizeof(rcc_translate_prefix_s) + len - sizeof(rcc_external_command_s);
+ err = rccExternalWrite(translate->sock, (char*)&translate->prefix, sizeof(rcc_translate_prefix_s) - 1, 0);
+ if (err) {
+ rccExternalClose(translate->sock);
+ translate->sock = -1;
+ return NULL;
+ }
+ err = rccExternalWrite(translate->sock, buf, len + 1, 0);
+ if (err) {
+ rccExternalClose(translate->sock);
+ translate->sock = -1;
+ return NULL;
+ }
+
+ err = rccExternalRead(translate->sock, (char*)&resp, sizeof(rcc_external_command_s), translate->prefix.timeout);
+ if (err) {
+ if (err == sizeof(rcc_external_command_s)) {
+ translate->remaining = (size_t)-1;
+ } else {
+ rccExternalClose(translate->sock);
+ translate->sock = -1;
+ }
+ return NULL;
+ }
+ if ((resp.cmd!=RCC_EXTERNAL_COMMAND_TRANSLATE)||(!resp.size)) return NULL;
+
+ buffer = (char*)malloc(resp.size*sizeof(char));
+ if (!buffer) {
+ rccExternalClose(translate->sock);
+ translate->sock = -1;
+ return NULL;
+ }
+ err = rccExternalRead(translate->sock, buffer, resp.size, 0);
+ if (err) {
+ translate->remaining = err;
+ free(buffer);
+ return NULL;
+ }
+
+ return buffer;
+#else
+ return NULL;
+#endif /* HAVE_LIBTRANSLATE */
+}
diff --git a/src/rcctranslate.h b/src/rcctranslate.h
new file mode 100644
index 0000000..961af6f
--- /dev/null
+++ b/src/rcctranslate.h
@@ -0,0 +1,31 @@
+#ifndef _RCC_TRANSLATE_H
+#define _RCC_TRANSLATE_H
+
+#include "rccexternal.h"
+#define RCC_TRANSLATE_DEFAULT_TIMEOUT 5000000 /* 5s */
+#define RCC_EXTERNAL_COMMAND_TRANSLATE 0x80
+
+
+struct rcc_translate_prefix_t {
+ rcc_external_command_s cmd;
+ unsigned long timeout;
+ char from[3];
+ char to[3];
+ char text[1];
+};
+typedef struct rcc_translate_prefix_t rcc_translate_prefix_s;
+typedef struct rcc_translate_prefix_t *rcc_translate_prefix;
+
+
+struct rcc_translate_t {
+ rcc_translate_prefix_s prefix;
+ size_t remaining;
+ int sock;
+};
+typedef struct rcc_translate_t rcc_translate_s;
+
+
+int rccTranslateInit();
+void rccTranslateFree();
+
+#endif /* _RCC_TRANSLATE_H */
diff --git a/src/recode.c b/src/recode.c
index a1b7f31..c44095c 100644
--- a/src/recode.c
+++ b/src/recode.c
@@ -9,6 +9,7 @@
#include "rccstring.h"
#include "rccconfig.h"
#include "rccdb4.h"
+#include "rcctranslate.h"
@@ -37,6 +38,7 @@ rcc_string rccSizedFrom(rcc_context ctx, rcc_class_id class_id, const char *buf,
rcc_iconv icnv = NULL;
rcc_string result;
rcc_option_value usedb4;
+ const char *charset;
if (!ctx) {
if (rcc_default_ctx) ctx = rcc_default_ctx;
@@ -66,11 +68,17 @@ rcc_string rccSizedFrom(rcc_context ctx, rcc_class_id class_id, const char *buf,
if (err) return NULL;
charset_id = rccIConvAuto(ctx, class_id, buf, len);
- if (charset_id != (rcc_autocharset_id)-1) icnv = ctx->iconv_auto[charset_id];
+ if (charset_id != (rcc_autocharset_id)-1) {
+ icnv = ctx->iconv_auto[charset_id];
+ if (rccGetOption(ctx, RCC_OPTION_AUTOENGINE_SET_CURRENT)) {
+ charset = rccGetAutoCharsetName(ctx, charset_id);
+ rccSetCharsetByName(ctx, class_id, charset);
+ }
+ }
else icnv = ctx->iconv_from[class_id];
if (icnv) {
- ret = rccIConv(ctx, icnv, buf, len);
+ ret = rccIConvInternal(ctx, icnv, buf, len);
if (ret == (size_t)-1) return NULL;
result = rccCreateString(language_id, ctx->tmpbuffer, ret);
} else {
@@ -92,8 +100,10 @@ char *rccSizedTo(rcc_context ctx, rcc_class_id class_id, rcc_const_string buf, s
char *result;
char *prefix, *name;
const char *utfstring;
+ char *translated = NULL;
rcc_language_config config;
rcc_language_id language_id;
+ rcc_language_id current_language_id;
rcc_class_type class_type;
rcc_iconv icnv;
@@ -117,6 +127,38 @@ char *rccSizedTo(rcc_context ctx, rcc_class_id class_id, rcc_const_string buf, s
if (err) return NULL;
class_type = rccGetClassType(ctx, class_id);
+ if ((class_type != RCC_CLASS_FS)&&(rccGetOption(ctx, RCC_OPTION_TRANSLATE))) {
+ current_language_id = rccGetCurrentLanguage(ctx);
+ if (current_language_id != language_id) {
+ if ((config->trans)&&(config->translang != current_language_id)) {
+ rccTranslateClose(config->trans);
+ config->trans = NULL;
+ }
+ if (!config->trans) {
+ config->trans = rccTranslateOpen(rccGetLanguageName(ctx, language_id), rccGetLanguageName(ctx, current_language_id));
+ config->translang = current_language_id;
+ }
+ if (config->trans) {
+ translated = rccTranslate(config->trans, utfstring);
+ if (translated) {
+ language_id = current_language_id;
+
+ config = rccGetConfig(ctx, language_id);
+ if (!config) {
+ free(translated);
+ return NULL;
+ }
+
+ err = rccConfigConfigure(config);
+ if (err) {
+ free(translated);
+ return NULL;
+ }
+ }
+ }
+ }
+ }
+
if ((class_type == RCC_CLASS_FS)&&(rccGetOption(ctx, RCC_OPTION_AUTODETECT_FS_NAMES))) {
if (rccIsASCII(utfstring)) {
result = rccStringExtractString(buf);
@@ -141,14 +183,20 @@ char *rccSizedTo(rcc_context ctx, rcc_class_id class_id, rcc_const_string buf, s
icnv = config->iconv_to[class_id];
if (icnv) {
- newlen = rccIConv(ctx, icnv, rccStringGetString((const char*)buf), newlen);
+ newlen = rccIConvInternal(ctx, icnv, translated?translated:utfstring, newlen);
+ if (translated) free(translated);
if (newlen == (size_t)-1) return NULL;
result = rccCreateResult(ctx, newlen);
if (rlen) *rlen = newlen;
} else {
- result = rccStringExtractString(buf);
- if (rlen) *rlen = newlen;
+ if (translated) {
+ result = translated;
+ if (rlen) *rlen = strlen(result);
+ } else {
+ result = rccStringExtractString(buf);
+ if (rlen) *rlen = newlen;
+ }
}
return result;
@@ -274,7 +322,7 @@ rcc_string rccSizedFromCharset(rcc_context ctx, const char *charset, const char
icnv = rccIConvOpen("UTF-8", charset);
if (icnv) {
- res = rccIConv(ctx, icnv, buf, len);
+ res = rccIConvInternal(ctx, icnv, buf, len);
rccIConvClose(icnv);
if (res == (size_t)-1) return NULL;
return rccCreateString(language_id, ctx->tmpbuffer, res);
@@ -293,7 +341,7 @@ char *rccSizedToCharset(rcc_context ctx, const char *charset, rcc_const_string b
icnv = rccIConvOpen(charset, "UTF-8");
if (icnv) {
- res = rccIConv(ctx, icnv, rccStringGetString(buf), res);
+ res = rccIConvInternal(ctx, icnv, rccStringGetString(buf), res);
rccIConvClose(icnv);
if (res == (size_t)-1) return NULL;
@@ -321,7 +369,7 @@ char *rccSizedRecodeToCharset(rcc_context ctx, rcc_class_id class_id, const char
icnv = rccIConvOpen(charset, "UTF-8");
if (icnv) {
- res = rccIConv(ctx, icnv, str, 0);
+ res = rccIConvInternal(ctx, icnv, str, 0);
rccIConvClose(icnv);
free(utf8);
@@ -349,7 +397,7 @@ char *rccSizedRecodeFromCharset(rcc_context ctx, rcc_class_id class_id, const ch
icnv = rccIConvOpen("UTF-8", charset);
if (icnv) {
- res = rccIConv(ctx, icnv, buf, len);
+ res = rccIConvInternal(ctx, icnv, buf, len);
rccIConvClose(icnv);
if (res == (size_t)-1) return NULL;
@@ -373,7 +421,7 @@ char *rccSizedRecodeCharsets(rcc_context ctx, const char *from, const char *to,
icnv = rccIConvOpen(to, from);
if (!icnv) return NULL;
- res = rccIConv(ctx, icnv, buf, len);
+ res = rccIConvInternal(ctx, icnv, buf, len);
rccIConvClose(icnv);
if (res == (size_t)-1) return NULL;
diff --git a/ui/librccui.c b/ui/librccui.c
index f072c6e..c4ac1c0 100644
--- a/ui/librccui.c
+++ b/ui/librccui.c
@@ -112,11 +112,12 @@ static xmlNodePtr rccUiNodeFind(xmlXPathContextPtr xpathctx, const char *request
fullname = rccUiXmlGetText(node); \
if (fullname) { \
if (icnv) { \
- newsize = rccIConvRecode(icnv, tmpbuf, RCC_UI_MAX_STRING_CHARS, fullname, 0); \
- if (newsize != (size_t)-1) { \
+ tmpbuf = rccIConv(icnv, fullname, 0, NULL); \
+ if (tmpbuf) { \
cnode = xmlNewChild(node->parent, NULL, "Recoded", tmpbuf); \
fullname = rccUiXmlGetText(cnode); \
if (!fullname) fullname = rccUiXmlGetText(node); \
+ free(tmpbuf); \
} \
} \
var = fullname; \
@@ -154,11 +155,12 @@ static xmlNodePtr rccUiNodeFind(xmlXPathContextPtr xpathctx, const char *request
fullname = rccUiXmlGetText(node); \
if (fullname) { \
if (icnv) { \
- newsize = rccIConvRecode(icnv, tmpbuf, RCC_UI_MAX_STRING_CHARS, fullname, 0); \
- if (newsize != (size_t)-1) { \
+ tmpbuf = rccIConv(icnv, fullname, 0, NULL); \
+ if (tmpbuf) { \
cnode = xmlNewChild(node->parent, NULL, "Recoded", tmpbuf); \
fullname = rccUiXmlGetText(cnode); \
if (!fullname) fullname = rccUiXmlGetText(node); \
+ free(tmpbuf); \
} \
} \
\
@@ -197,8 +199,7 @@ int rccUiInit() {
unsigned int npos;
- size_t newsize;
- char tmpbuf[RCC_UI_MAX_STRING_CHARS+1];
+ char *tmpbuf;
char ctype_charset[32];
char locale[32];
rcc_iconv icnv;
@@ -271,11 +272,12 @@ int rccUiInit() {
if (!fullname) continue;
if (icnv) {
- newsize = rccIConvRecode(icnv, tmpbuf, RCC_UI_MAX_STRING_CHARS, fullname, 0);
- if (newsize != (size_t)-1) {
+ tmpbuf = rccIConv(icnv, fullname, 0, NULL);
+ if (tmpbuf) {
cnode = xmlNewChild(node->parent, NULL, "Recoded", tmpbuf);
fullname = rccUiXmlGetText(cnode);
if (!fullname) fullname = rccUiXmlGetText(node);
+ free(tmpbuf);
}
}
@@ -319,11 +321,12 @@ int rccUiInit() {
fullname = rccUiXmlGetText(node);
if (fullname) {
if (icnv) {
- newsize = rccIConvRecode(icnv, tmpbuf, RCC_UI_MAX_STRING_CHARS, fullname, 0);
- if (newsize != (size_t)-1) {
+ tmpbuf = rccIConv(icnv, fullname, 0, NULL);
+ if (tmpbuf) {
cnode = xmlNewChild(node->parent, NULL, "Recoded", tmpbuf);
fullname = rccUiXmlGetText(cnode);
if (!fullname) fullname = rccUiXmlGetText(node);
+ free(tmpbuf);
}
}
option_name->name = fullname;
@@ -346,11 +349,12 @@ int rccUiInit() {
fullname = rccUiXmlGetText(node);
if (fullname) {
if (icnv) {
- newsize = rccIConvRecode(icnv, tmpbuf, RCC_UI_MAX_STRING_CHARS, fullname, 0);
- if (newsize != (size_t)-1) {
+ tmpbuf = rccIConv(icnv, fullname, 0, NULL);
+ if (tmpbuf) {
cnode = xmlNewChild(node->parent, NULL, "Recoded", tmpbuf);
fullname = rccUiXmlGetText(cnode);
if (!fullname) fullname = rccUiXmlGetText(node);
+ free(tmpbuf);
}
}
option_name->value_names[k] = fullname;
diff --git a/ui/rccnames.c b/ui/rccnames.c
index 1e79e5b..b6d08dd 100644
--- a/ui/rccnames.c
+++ b/ui/rccnames.c
@@ -11,6 +11,7 @@ rcc_name rcc_default_language_names[RCC_MAX_LANGUAGES+1];
rcc_name rcc_default_language_names_embeded[RCC_MAX_LANGUAGES+1] = {
{"default", "Autodetect"},
{"off", "Dissable"},
+{"en", "English" },
{"ru","Russian"},
{"uk","Ukrainian"},
{"be","Belarussian"},
@@ -38,6 +39,8 @@ rcc_option_name rcc_default_option_names_embeded[RCC_MAX_OPTIONS+1] = {
{ RCC_OPTION_AUTODETECT_FS_NAMES, "Autodetect File Names", rcc_default_option_boolean_names },
{ RCC_OPTION_AUTODETECT_FS_TITLES, "Autodetect FS Titles", rcc_default_option_boolean_names },
{ RCC_OPTION_CONFIGURED_LANGUAGES_ONLY, "Enabled Languages", rcc_default_option_clo_names },
+ { RCC_OPTION_TRANSLATE, "Translate Text", rcc_default_option_boolean_names },
+ { RCC_OPTION_AUTOENGINE_SET_CURRENT, "AutoEngine Set Current Encoding", rcc_default_option_boolean_names },
{ RCC_MAX_OPTIONS }
};