diff options
-rw-r--r-- | Makefile.am | 2 | ||||
-rw-r--r-- | README | 9 | ||||
-rw-r--r-- | ToDo | 20 | ||||
-rw-r--r-- | VERSION | 2 | ||||
-rw-r--r-- | configure.in | 42 | ||||
-rw-r--r-- | examples/Makefile.am | 12 | ||||
-rw-r--r-- | examples/example1.c (renamed from examples/example.c) | 0 | ||||
-rw-r--r-- | examples/example2.c | 60 | ||||
-rw-r--r-- | examples/rcc-gtk-config.c | 6 | ||||
-rw-r--r-- | external/Makefile.am | 12 | ||||
-rw-r--r-- | external/rccexternal.c | 117 | ||||
-rw-r--r-- | external/rcclibtranslate.c | 286 | ||||
-rw-r--r-- | external/rcclibtranslate.h | 9 | ||||
-rw-r--r-- | src/Makefile.am | 2 | ||||
-rw-r--r-- | src/fs.c | 2 | ||||
-rw-r--r-- | src/librcc.c | 45 | ||||
-rw-r--r-- | src/librcc.h | 58 | ||||
-rw-r--r-- | src/lngconfig.c | 7 | ||||
-rw-r--r-- | src/lngconfig.h | 4 | ||||
-rw-r--r-- | src/rccconfig.c | 6 | ||||
-rw-r--r-- | src/rccdb4.c | 41 | ||||
-rw-r--r-- | src/rccdb4.h | 8 | ||||
-rw-r--r-- | src/rccexternal.c | 210 | ||||
-rw-r--r-- | src/rccexternal.h | 35 | ||||
-rw-r--r-- | src/rcciconv.c | 23 | ||||
-rw-r--r-- | src/rcciconv.h | 14 | ||||
-rw-r--r-- | src/rcctranslate.c | 151 | ||||
-rw-r--r-- | src/rcctranslate.h | 31 | ||||
-rw-r--r-- | src/recode.c | 68 | ||||
-rw-r--r-- | ui/librccui.c | 28 | ||||
-rw-r--r-- | ui/rccnames.c | 3 |
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 @@ -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 @@ -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 @@ -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 @@ -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 } }; |