From e3f702e83a26468ee44f3f342a7a40a252f4603c Mon Sep 17 00:00:00 2001 From: "Suren A. Chilingaryan" Date: Fri, 29 Jul 2005 03:26:28 +0000 Subject: Translation - Language Translation using libtranslate is implemented - Autoengine sets current charset (option) --- src/Makefile.am | 2 + src/fs.c | 2 +- src/librcc.c | 45 ++++++++++++ src/librcc.h | 58 +++++++++++++-- src/lngconfig.c | 7 +- src/lngconfig.h | 4 + src/rccconfig.c | 6 ++ src/rccdb4.c | 41 +---------- src/rccdb4.h | 8 +- src/rccexternal.c | 210 +++++++++++++++++++++++++++++++++++++++++++++++++++++ src/rccexternal.h | 35 +++++++++ src/rcciconv.c | 23 +++++- src/rcciconv.h | 14 +++- src/rcctranslate.c | 151 ++++++++++++++++++++++++++++++++++++++ src/rcctranslate.h | 31 ++++++++ src/recode.c | 68 ++++++++++++++--- 16 files changed, 642 insertions(+), 63 deletions(-) create mode 100644 src/rccexternal.c create mode 100644 src/rccexternal.h create mode 100644 src/rcctranslate.c create mode 100644 src/rcctranslate.h (limited to 'src') 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 #endif /* HAVE_SYS_TYPES_H */ +#ifdef HAVE_SYS_STAT_H +# include +#endif /* HAVE_SYS_STAT_H */ #ifdef HAVE_PWD_H # include @@ -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 */ /** @@ -1118,6 +1159,11 @@ rcc_context rccEngineGetRccContext(rcc_engine_context ctx); * LibRCD engine is compiled in */ #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 */ 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 -#endif /* HAVE_SYS_TYPES_H */ - -#ifdef HAVE_SYS_STAT_H -# include -#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 #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 +#include +#include +#include +#include + +#include "../config.h" + +#ifdef HAVE_UNISTD_H +# include +#endif /* HAVE_UNISTD_H */ +#ifdef HAVE_FCNTL_H +# include +#endif /* HAVE_FCNTL_H */ +#ifdef HAVE_SIGNAL_H +# include +#endif /* HAVE_SIGNAL_H */ + +#ifdef HAVE_SYS_TYPES_H +# include +#endif /* HAVE_SYS_TYPES_H */ +#ifdef HAVE_SYS_SOCKET_H +# include +#endif /* HAVE_SYS_SOCKET_H */ +#ifdef HAVE_SYS_STAT_H +# include +#endif /* HAVE_SYS_STAT_H */ +#ifdef HAVE_SYS_UN_H +# include +#endif /* HAVE_SYS_UN_H */ +#ifdef HAVE_SYS_TIME_H +# include +#endif /* HAVE_SYS_TIME_H */ +#ifdef HAVE_SYS_SELECT_H +# include +#endif /* HAVE_SYS_SELECT_H */ +#ifdef HAVE_SYS_WAIT_H +# include +#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 +#include +#include + +#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; -- cgit v1.2.3