summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am6
-rw-r--r--src/config.c104
-rw-r--r--src/config.h17
-rw-r--r--src/db4.c0
-rw-r--r--src/db4.h5
-rw-r--r--src/enca.c161
-rw-r--r--src/enca.h19
-rw-r--r--src/engine.c56
-rw-r--r--src/engine.h11
-rw-r--r--src/fake_enca.h289
-rw-r--r--src/fs.c172
-rw-r--r--src/fs.h9
-rw-r--r--src/librcc.c312
-rw-r--r--src/librcc.h271
-rw-r--r--src/lng.c135
-rw-r--r--src/lngconfig.c363
-rw-r--r--src/plugin.c31
-rw-r--r--src/plugin.h15
-rw-r--r--src/recode.c228
-rw-r--r--src/string.c74
-rw-r--r--src/xml.c8
21 files changed, 2286 insertions, 0 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
new file mode 100644
index 0000000..d555299
--- /dev/null
+++ b/src/Makefile.am
@@ -0,0 +1,6 @@
+lib_LTLIBRARIES = librcc.la
+librcc_la_SOURCES = librcc.c lng.c lngconfig.c recode.c config.c config.h plugin.c plugin.h enca.c enca.h engine.c engine.h
+include_HEADERS = librcc.h
+
+librcc_la_LDFLAGS = -version-info @LIBRCC_VERSION_INFO@
+
diff --git a/src/config.c b/src/config.c
new file mode 100644
index 0000000..885f416
--- /dev/null
+++ b/src/config.c
@@ -0,0 +1,104 @@
+#include <stdio.h>
+#include <librcd.h>
+
+static rcc_charset_id rcc_autoengine_russian(rcc_engine_context ctx, char *buf, int len) {
+ return (int)get_russian_charset(buf,len);
+}
+
+rcc_language_alias rcc_default_aliases[] = {
+ { "cs_SK", "sk" },
+ { "ru_UA", "uk" },
+ { NULL, NULL}
+};
+
+const char rcc_engine_nonconfigured[] = "NonConfigured";
+
+rcc_engine rcc_default_engine = {
+ "Off", NULL, NULL, NULL, {NULL}
+};
+
+rcc_engine rcc_russian_engine = {
+ "Russian", NULL, NULL, &rcc_autoengine_russian, {"CP1251","KOI8-R","UTF-8","IBM866", NULL}
+};
+
+rcc_language rcc_default_languages[] = {
+{"default", "Autodetect", {"Default", NULL} {
+ &default_engine,
+ NULL
+}},
+{"off", "Dissable", {"Default", NULL} {
+ &default_engine,
+ NULL
+}},
+{"ru","Russian",{"Default","KOI8-R","CP1251","UTF-8","IBM866","MACCYRILLIC","ISO8859-5", NULL},{
+ &default_engine,
+ &russian_engine,
+ NULL
+}},
+{"uk","Ukrainian",{"Default","KOI8-U","CP1251","UTF-8","IBM855","MACCYRILLIC","ISO8859-5","CP1125", NULL},{
+ &default_engine,
+ &russian_engine,
+ NULL
+}},
+{"be","Belarussian",{"Default", "UTF-8", "CP1251", "IBM866", "ISO-8859-5", "KOI8-UNI", "maccyr" "IBM855", NULL},{
+ &default_engine,
+ NULL
+}},
+{"bg","Bulgarian",{"Default", "UTF-8", "CP1251", "ISO-8859-5", "IBM855", "maccyr", "ECMA-113", NULL},{
+ &default_engine,
+ NULL
+}},
+{"cz","Czech",{"Default", "UTF-8", "ISO-8859-2", "CP1250", "IBM852", "KEYBCS2", "macce", "KOI-8_CS_2", "CORK", NULL},{
+ &default_engine,
+ NULL
+}},
+{"es","Estonian",{"Default", "UTF-8", "ISO-8859-4", "CP1257", "IBM775", "ISO-8859-13", "macce", "baltic", NULL},{
+ &default_engine,
+ NULL
+}},
+{"hr","Croatian",{"Default", "UTF-8", "CP1250", "ISO-8859-2", "IBM852", "macce", "CORK", NULL},{
+ &default_engine,
+ NULL
+}},
+{"hu","Hungarian",{"Default", "UTF-8", "ISO-8859-2", "CP1250", "IBM852", "macce", "CORK", NULL},{
+ &default_engine,
+ NULL
+}},
+{"lt","Lithuanian",{"Default", "UTF-8", "CP1257", "ISO-8859-4", "IBM775", "ISO-8859-13", "macce", "baltic", NULL},{
+ &default_engine,
+ NULL
+}},
+{"lv","Latvian",{"Default", "UTF-8", "CP1257", "ISO-8859-4", "IBM775", "ISO-8859-13", "macce", "baltic", NULL},{
+ &default_engine,
+ NULL
+}},
+{"pl","Polish",{"Default", "UTF-8", "ISO-8859-2", "CP1250", "IBM852", "macce", "ISO-8859-13", "ISO-8859-16", "baltic", "CORK", NULL},{
+ &default_engine,
+ NULL
+}},
+{"sk","Slovak",{"Default", "UTF-8", "CP1250", "ISO-8859-2", "IBM852", "KEYBCS2", "macce", "KOI-8_CS_2", "CORK", NULL},{
+ &default_engine,
+ NULL
+}},
+{"sl","Slovenian",{"Default", "UTF-8", "ISO-8859-2", "CP1250", "IBM852", "macce", "CORK", NULL},{
+ &default_engine,
+ NULL
+}},
+{"zh","Chinese",{"Default", "UTF-8", "GB2312", "GBK", "GB18030", "BIG5", NULL},{
+ &default_engine,
+ NULL
+}},
+NULL
+};
+
+/*
+const charset_list_t charset_list_default = { "Default", NULL };
+charset_t *charset_list=(charset_t*)charset_list_default;
+#define autocharset_list_ni_default 1
+autocharset_list_t autocharset_list_default = {
+ {"Off", NULL, {NULL}}
+};
+
+int autocharset_list_ni=autocharset_list_ni_default;
+autocharset_t *autocharset_list=(autocharset_t*)autocharset_list_default;
+*/ \ No newline at end of file
diff --git a/src/config.h b/src/config.h
new file mode 100644
index 0000000..ac74dbe
--- /dev/null
+++ b/src/config.h
@@ -0,0 +1,17 @@
+#ifndef _RCC_CONFIG_H
+#define _RCC_CONFIG_H
+#include "librcc.h"
+
+#undef RCC_DEBUG
+#define RCC_LOCALE_VARIABLE "LC_CTYPE"
+
+extern rcc_language_alias rcc_default_aliases[];
+
+extern const char rcc_engine_nonconfigured[];
+
+extern rcc_engine rcc_default_engine;
+extern rcc_engine rcc_russian_engine;
+
+extern rcc_language rcc_default_languages[];
+
+#endif /* _RCC_CONFIG_H */
diff --git a/src/db4.c b/src/db4.c
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/db4.c
diff --git a/src/db4.h b/src/db4.h
new file mode 100644
index 0000000..e13dd5f
--- /dev/null
+++ b/src/db4.h
@@ -0,0 +1,5 @@
+#ifndef _RCC_DB4_H
+#define _RCC_DB4_H
+
+
+#endif /* _RCC_DB4_H */
diff --git a/src/enca.c b/src/enca.c
new file mode 100644
index 0000000..95e2f49
--- /dev/null
+++ b/src/enca.c
@@ -0,0 +1,161 @@
+#include <stdio.h>
+
+#include "librcc.h"
+
+#include "plugin.h"
+#include "enca.h"
+
+rcc_engine rcc_enca_engine = {
+ "Enca Library", &rccEncaInitContext, &rccEncaFreeContext, &rccEnca, {"UTF-8", NULL}
+};
+
+static rcc_library_handle enca_handle = NULL;
+static rcc_engine enca_engines[sizeof(rcc_default_languages)/sizeof(rcc_language)];
+
+
+static int rccEncaLibraryLoad() {
+#ifdef RCC_ENCA_DYNAMIC
+ if (enca_handle) return 0;
+
+ enca_handle = rccLibraryLoad(RCC_ENCA_LIB);
+ if (!enca_handle) return -1;
+
+ enca_set_multibyte=rccLibraryFind(enca_handle,"enca_set_multibyte");
+ enca_set_interpreted_surfaces=rccLibraryFind(enca_handle,"enca_set_interpreted_surfaces");
+ enca_set_ambiguity=rccLibraryFind(enca_handle,"enca_set_ambiguity");
+ enca_set_filtering=rccLibraryFind(enca_handle,"enca_set_filtering");
+ enca_set_garbage_test=rccLibraryFind(enca_handle,"enca_set_garbage_test");
+ enca_set_termination_strictness=rccLibraryFind(enca_handle,"enca_set_termination_strictness");
+ enca_set_significant=rccLibraryFind(enca_handle,"enca_set_significant");
+ enca_set_threshold=rccLibraryFind(enca_handle,"enca_set_threshold");
+ enca_charset_name=rccLibraryFind(enca_handle,"enca_charset_name");
+ enca_get_language_charsets=rccLibraryFind(enca_handle,"enca_get_language_charsets");
+ enca_analyser_alloc=rccLibraryFind(enca_handle,"enca_analyser_alloc");
+ enca_analyser_free=rccLibraryFind(enca_handle,"enca_analyser_free");
+ enca_analyse_const=rccLibraryFind(enca_handle,"enca_analyse_const");
+
+ if ((!enca_set_multibyte)||(!enca_set_interpreted_surfaces)||(!enca_set_ambiguity)||
+ (!enca_set_filtering)||(!enca_set_garbage_test)||(!enca_set_termination_strictness)||
+ (!enca_set_significant)||(!enca_set_threshold)||(!enca_charset_name)||
+ (!enca_get_language_charsets)||(!enca_analyser_alloc)||(!enca_analyser_free)||
+ (!enca_analyse_const)) {
+ rccLibraryClose(enca_handle);
+ enca_handle = NULL;
+# ifdef RCC_DEBUG
+ perror( "rccEnca. Incomplete function set in library" );
+# endif /* RCC_DEBUG */
+ }
+
+#endif /* RCC_ENCA_DYNAMIC */
+ return 0;
+}
+
+static void rccEncaLibraryUnload() {
+#ifdef RCC_ENCA_DYNAMIC
+ if (enca_handle) {
+ rccLibraryUnload(enca_handle);
+ enca_handle = NULL;
+ }
+#endif /* RCC_ENCA_DYNAMIC */
+}
+
+
+int rccEncaInit() {
+ int err;
+ unsigned int i,j,k,l;
+
+ rcc_engine_list engines;
+
+ int *charsets;
+ size_t ncharsets;
+
+#ifdef RCC_ENCA_SUPPORT
+ err = rccEncaLibraryLoad();
+ if (err) return err;
+
+ for (i=0;rcc_default_languages[i];i++) {
+ engines = rcc_default_languages[i].engines;
+ for (j=0;engines[j];j++)
+ if (j >= RCC_MAX_ENGINES) continue;
+
+ charsets = enca_get_language_charsets(rcc_default_languages[i].sn, &ncharsets);
+ if (charsets) {
+ memcpy(enca_engines+i, &rcc_enca_engine, sizeof(rcc_engine));
+ for (k=0;enca_engines[i].charsets[k];k++);
+ if (n_charsets+k>=RCC_MAX_CHARSETS) n_charsets = RCC_MAX_CHARSETS-k;
+
+ for (l=0;l<n_charsets;l++)
+ enca_engines[j].charset[k++] = enca_charset_name(charsets[l], ENCA_NAME_STYLE_ICONV);
+ enca_engines[j].charset[k] = NULL;
+
+ engines[j] = enca_engines + i;
+ engines[j+1] = NULL;
+
+ free(charsets);
+ }
+ }
+#endif /* RCC_ENCA_SUPPORT */
+
+ return 0;
+}
+
+void rccEncaFree() {
+#ifdef RCC_ENCA_SUPPORT
+ rccEncaLibraryUnload();
+#endif /* RCC_ENCA_SUPPORT */
+}
+
+
+rcc_engine_internal rccEncaInitContext(rcc_engine_context *ctx) {
+#ifdef RCC_ENCA_SUPPORT
+ EncaAnalyser enca;
+
+ if ((!ctx)||(!ctx->language)) return NULL;
+
+ enca = enca_analyser_alloc(ctx->lanuage->sn);
+ if (!enca) return NULL;
+
+ enca_set_threshold(enca, 1);
+ enca_set_multibyte(enca, 1);
+ enca_set_ambiguity(enca, 1);
+ enca_set_garbage_test(enca, 0);
+ enca_set_filtering(enca, 0);
+ enca_set_significant(enca,1);
+ enca_set_termination_strictness(enca,0);
+
+ return (rcc_engine_internal)enca;
+#else /* RCC_ENCA_SUPPORT */
+ return NULL;
+#endif /* RCC_ENCA_SUPPORT */
+}
+
+void rccEncaFreeContext(rcc_engine_context ctx) {
+ rcc_engine_internal internal;
+#ifdef RCC_ENCA_SUPPORT
+ internal = rccEngineGetInternal(ctx);
+ if (internal)
+ enca_analyser_free(internal);
+#endif /* RCC_ENCA_SUPPORT */
+}
+
+rcc_charset_id rccEnca(rcc_engine_context ctx, char *buf, int len) {
+#ifdef RCC_ENCA_SUPPORT
+ rcc_engine_internal internal;
+ const char *charset;
+ EncaEncoding ee;
+
+ internal = rccEngineGetInternal(ctx);
+ if ((!internal)||(!buf)) return -1;
+
+
+ len = STRLEN(buf, len);
+
+ ee = enca_analyse_const((EncaAnalyser)ctx->internal,buf,len);
+ if (ee.charset<0) return -1;
+
+ charset = enca_charset_name(ee.charset, ENCA_NAME_STYLE_ICONV);
+ return rccGetAutoCharsetByName(ctx->ctx, charset);
+#else /* RCC_ENCA_SUPPORT */
+ return -1;
+#endif /* RCC_ENCA_SUPPORT */
+}
diff --git a/src/enca.h b/src/enca.h
new file mode 100644
index 0000000..7e3d139
--- /dev/null
+++ b/src/enca.h
@@ -0,0 +1,19 @@
+#ifndef _RCC_ENCA_H
+#define _RCC_ENCA_H
+
+#define RCC_ENCA_SUPPORT
+#define RCC_ENCA_DYNAMIC
+#define RCC_ENCA_LIB "libenca.so.0"
+
+#ifdef HPUX
+# undef RCC_ENCA_DYNAMIC
+#endif
+
+#ifdef RCC_ENCA_DYNAMIC
+# define RCC_ENCA_SUPPORT
+#endif
+
+int rccEncaInit();
+void rccEncaFree();
+
+#endif /* _RCC_ENCA_H */ \ No newline at end of file
diff --git a/src/engine.c b/src/engine.c
new file mode 100644
index 0000000..646d46e
--- /dev/null
+++ b/src/engine.c
@@ -0,0 +1,56 @@
+#include <stdio.h>
+#include <string.h>
+
+#include "librcc.h"
+
+int rccEngineInit(rcc_engine_context *engine_ctx, rcc_context *ctx) {
+ if ((!ctx)||(!engine_ctx)) return -1;
+
+ engine_ctx->ctx = ctx;
+ engine_ctx->free_func = NULL;
+ engine_ctx->func = NULL;
+ return 0;
+}
+
+void rccFreeEngine(rcc_engine_context *engine_ctx) {
+ if (!engine_ctx) return;
+
+ if (engine_ctx->free_func) {
+ engine_ctx->free_func(engine_ctx);
+ engine_ctx->free_func = NULL;
+ }
+
+ engine_ctx->func = NULL;
+ engine_ctx->internal = NULL;
+}
+
+int rccEngineConfigure(rcc_engine_context *ctx) {
+ rcc_language_id language_id;
+ rcc_engine_id engine_id;
+ rcc_engine *engine;
+
+ if ((!ctx)||(!ctx->ctx)) return -1;
+
+ rccEngineFree(&ctx);
+
+ language_id = rccGetCurrentLanguage(ctx->ctx);
+ if (language_id<0) return -1;
+
+ engine_id = rccGetCurrentEngine(ctx->ctx);
+ if (engine_id<0) return -1;
+
+ engine = ctx->ctx->languages[language_id]->engines[engine_id];
+
+ ctx->free_func = engine->free_func;
+ ctx->func = engine->func;
+ ctx->language = ctx->languages[language_id];
+
+ ctx->internal = engine->init_func(ctx);
+ return 0;
+}
+
+rcc_engine_internal rccEngineGetInternal(rcc_engine_context *ctx) {
+ if (!ctx) return NULL;
+
+ return ctx->internal;
+}
diff --git a/src/engine.h b/src/engine.h
new file mode 100644
index 0000000..8f7400a
--- /dev/null
+++ b/src/engine.h
@@ -0,0 +1,11 @@
+#ifndef _RCC_ENGINE_H
+#defien _RCC_ENGINE_H
+
+int rccEngineInit(rcc_engine_context *engine_ctx, rcc_context *ctx);
+void rccFreeEngine(rcc_engine_context *engine_ctx);
+
+int rccConfigure(rcc_engine_context *ctx);
+
+rcc_engine_internal rccEngineGetInternal(rcc_engine_context *ctx);
+
+#endif /* _RCC_ENGINE_H */
diff --git a/src/fake_enca.h b/src/fake_enca.h
new file mode 100644
index 0000000..4483efb
--- /dev/null
+++ b/src/fake_enca.h
@@ -0,0 +1,289 @@
+/* This header file is in the public domain. */
+#ifndef ENCA_H
+#define ENCA_H
+
+#include <stdlib.h>
+/* According to autoconf stdlib may not be enough for size_t */
+#include <sys/types.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+/* Enumerated types */
+
+/**
+ * EncaSurface:
+ * @ENCA_SURFACE_EOL_CR: End-of-lines are represented with CR's.
+ * @ENCA_SURFACE_EOL_LF: End-of-lines are represented with LF's.
+ * @ENCA_SURFACE_EOL_CRLF: End-of-lines are represented with CRLF's.
+ * @ENCA_SURFACE_EOL_MIX: Several end-of-line types, mixed.
+ * @ENCA_SURFACE_EOL_BIN: End-of-line concept not applicable (binary data).
+ * @ENCA_SURFACE_MASK_EOL: Mask for end-of-line surfaces.
+ * @ENCA_SURFACE_PERM_21: Odd and even bytes swapped.
+ * @ENCA_SURFACE_PERM_4321: Reversed byte sequence in 4byte words.
+ * @ENCA_SURFACE_PERM_MIX: Chunks with both endianess, concatenated.
+ * @ENCA_SURFACE_MASK_PERM: Mask for permutation surfaces.
+ * @ENCA_SURFACE_QP: Quoted printables.
+ * @ENCA_SURFACE_REMOVE: Recode `remove' surface.
+ * @ENCA_SURFACE_UNKNOWN: Unknown surface.
+ * @ENCA_SURFACE_MASK_ALL: Mask for all bits, withnout #ENCA_SURFACE_UNKNOWN.
+ *
+ * Surface flags.
+ **/
+typedef enum { /*< flags >*/
+ ENCA_SURFACE_EOL_CR = 1 << 0,
+ ENCA_SURFACE_EOL_LF = 1 << 1,
+ ENCA_SURFACE_EOL_CRLF = 1 << 2,
+ ENCA_SURFACE_EOL_MIX = 1 << 3,
+ ENCA_SURFACE_EOL_BIN = 1 << 4,
+ ENCA_SURFACE_MASK_EOL = (ENCA_SURFACE_EOL_CR
+ | ENCA_SURFACE_EOL_LF
+ | ENCA_SURFACE_EOL_CRLF
+ | ENCA_SURFACE_EOL_MIX
+ | ENCA_SURFACE_EOL_BIN),
+ ENCA_SURFACE_PERM_21 = 1 << 5,
+ ENCA_SURFACE_PERM_4321 = 1 << 6,
+ ENCA_SURFACE_PERM_MIX = 1 << 7,
+ ENCA_SURFACE_MASK_PERM = (ENCA_SURFACE_PERM_21
+ | ENCA_SURFACE_PERM_4321
+ | ENCA_SURFACE_PERM_MIX),
+ ENCA_SURFACE_QP = 1 << 8,
+ ENCA_SURFACE_REMOVE = 1 << 13,
+ ENCA_SURFACE_UNKNOWN = 1 << 14,
+ ENCA_SURFACE_MASK_ALL = (ENCA_SURFACE_MASK_EOL
+ | ENCA_SURFACE_MASK_PERM
+ | ENCA_SURFACE_QP
+ | ENCA_SURFACE_REMOVE)
+} EncaSurface;
+
+/**
+ * EncaNameStyle:
+ * @ENCA_NAME_STYLE_ENCA: Default, implicit charset name in Enca.
+ * @ENCA_NAME_STYLE_RFC1345: RFC 1345 charset name.
+ * @ENCA_NAME_STYLE_CSTOCS: Cstocs charset name.
+ * @ENCA_NAME_STYLE_ICONV: Iconv charset name.
+ * @ENCA_NAME_STYLE_HUMAN: Human comprehensible description.
+ *
+ * Charset naming styles and conventions.
+ **/
+typedef enum {
+ ENCA_NAME_STYLE_ENCA,
+ ENCA_NAME_STYLE_RFC1345,
+ ENCA_NAME_STYLE_CSTOCS,
+ ENCA_NAME_STYLE_ICONV,
+ ENCA_NAME_STYLE_HUMAN
+} EncaNameStyle;
+
+/**
+ * EncaCharsetFlags:
+ * @ENCA_CHARSET_7BIT: Characters are represented with 7bit characters.
+ * @ENCA_CHARSET_8BIT: Characters are represented with bytes.
+ * @ENCA_CHARSET_16BIT: Characters are represented with 2byte words.
+ * @ENCA_CHARSET_32BIT: Characters are represented with 4byte words.
+ * @ENCA_CHARSET_FIXED: One characters consists of one fundamental piece.
+ * @ENCA_CHARSET_VARIABLE: One character consists of variable number of
+ * fundamental pieces.
+ * @ENCA_CHARSET_BINARY: Charset is binary from ASCII viewpoint.
+ * @ENCA_CHARSET_REGULAR: Language dependent (8bit) charset.
+ * @ENCA_CHARSET_MULTIBYTE: Multibyte charset.
+ *
+ * Charset properties.
+ *
+ * Flags %ENCA_CHARSET_7BIT, %ENCA_CHARSET_8BIT, %ENCA_CHARSET_16BIT,
+ * %ENCA_CHARSET_32BIT tell how many bits a `fundamental piece' consists of.
+ * This is different from bits per character; r.g. UTF-8 consists of 8bit
+ * pieces (bytes), but character can be composed from 1 to 6 of them.
+ **/
+typedef enum { /*< flags >*/
+ ENCA_CHARSET_7BIT = 1 << 0,
+ ENCA_CHARSET_8BIT = 1 << 1,
+ ENCA_CHARSET_16BIT = 1 << 2,
+ ENCA_CHARSET_32BIT = 1 << 3,
+ ENCA_CHARSET_FIXED = 1 << 4,
+ ENCA_CHARSET_VARIABLE = 1 << 5,
+ ENCA_CHARSET_BINARY = 1 << 6,
+ ENCA_CHARSET_REGULAR = 1 << 7,
+ ENCA_CHARSET_MULTIBYTE = 1 << 8
+} EncaCharsetFlags;
+
+/**
+ * EncaErrno:
+ * @ENCA_EOK: OK.
+ * @ENCA_EINVALUE: Invalid value (usually of an option).
+ * @ENCA_EEMPTY: Sample is empty.
+ * @ENCA_EFILTERED: After filtering, (almost) nothing remained.
+ * @ENCA_ENOCS8: Mulitibyte tests failed and language contains no 8bit charsets.
+ * @ENCA_ESIGNIF: Too few significant characters.
+ * @ENCA_EWINNER: No clear winner.
+ * @ENCA_EGARBAGE: Sample is garbage.
+ *
+ * Error codes.
+ **/
+typedef enum {
+ ENCA_EOK = 0,
+ ENCA_EINVALUE,
+ ENCA_EEMPTY,
+ ENCA_EFILTERED,
+ ENCA_ENOCS8,
+ ENCA_ESIGNIF,
+ ENCA_EWINNER,
+ ENCA_EGARBAGE
+} EncaErrno;
+
+/**
+ * ENCA_CS_UNKNOWN:
+ *
+ * Unknown character set id.
+ *
+ * Use enca_charset_is_known() to check for unknown charset instead of direct
+ * comparsion.
+ **/
+#define ENCA_CS_UNKNOWN (-1)
+
+/**
+ * ENCA_NOT_A_CHAR:
+ *
+ * Not-a-character in unicode tables.
+ **/
+#define ENCA_NOT_A_CHAR 0xffff
+
+/* Published (opaque) typedefs */
+typedef struct _EncaAnalyserState *EncaAnalyser;
+
+/* Public (transparent) typedefs */
+typedef struct _EncaEncoding EncaEncoding;
+
+/**
+ * EncaEncoding:
+ * @charset: Numeric charset identifier.
+ * @surface: Surface flags.
+ *
+ * Encoding, i.e. charset and surface.
+ *
+ * This is what enca_analyse() and enca_analyse_const() return.
+ *
+ * The @charset field is an opaque numerical charset identifier, which has no
+ * meaning outside Enca library.
+ * You will probably want to use it only as enca_charset_name() argument.
+ * It is only guaranteed not to change meaning
+ * during program execution time; change of its interpretation (e.g. due to
+ * addition of new charsets) is not considered API change.
+ *
+ * The @surface field is a combination of #EncaSurface flags. You may want
+ * to ignore it completely; you should use enca_set_interpreted_surfaces()
+ * to disable weird surfaces then.
+ **/
+struct _EncaEncoding { int charset; EncaSurface surface; };
+
+void (*enca_set_multibyte) (EncaAnalyser analyser, int multibyte);
+void (*enca_set_interpreted_surfaces) (EncaAnalyser analyser, int interpreted_surfaces);
+void (*enca_set_ambiguity) (EncaAnalyser analyser, int ambiguity);
+void (*enca_set_filtering) (EncaAnalyser analyser, int filtering);
+void (*enca_set_garbage_test) (EncaAnalyser analyser, int garabage_test);
+void (*enca_set_termination_strictness) (EncaAnalyser analyser, int termination_strictness);
+int (*enca_set_significant) (EncaAnalyser analyser, size_t significant);
+int (*enca_set_threshold) (EncaAnalyser analyser, double threshold);
+const char* (*enca_charset_name) (int charset, EncaNameStyle whatname);
+int* (*enca_get_language_charsets) (const char *langname, size_t *n);
+EncaAnalyser (*enca_analyser_alloc) (const char *langname);
+void (*enca_analyser_free) (EncaAnalyser analyser);
+EncaEncoding (*enca_analyse_const) (EncaAnalyser analyser,const unsigned char *buffer, size_t size);
+
+/**
+ * enca_charset_is_known:
+ * @cs: Charset id.
+ *
+ * Expands to nonzero when the charset is known (i.e. it's not
+ * ENCA_CS_UNKNOWN).
+ **/
+#define enca_charset_is_known(cs) \
+ ((cs) != ENCA_CS_UNKNOWN)
+
+/**
+ * enca_charset_is_7bit:
+ * @cs: Charset id.
+ *
+ * Expands to nonzero when characters are represented with 7bit characters.
+ **/
+#define enca_charset_is_7bit(cs) \
+ (enca_charset_properties(cs) & ENCA_CHARSET_7BIT)
+
+/**
+ * enca_charset_is_8bit:
+ * @cs: Charset id.
+ *
+ * Expands to nonzero when characters are represented with bytes.
+ **/
+#define enca_charset_is_8bit(cs) \
+ (enca_charset_properties(cs) & ENCA_CHARSET_8BIT)
+
+/**
+ * enca_charset_is_16bit:
+ * @cs: Charset id.
+ *
+ * Expands to nonzero when characters are represented with 2byte words.
+ **/
+#define enca_charset_is_16bit(cs) \
+ (enca_charset_properties(cs) & ENCA_CHARSET_16BIT)
+
+/**
+ * enca_charset_is_32bit:
+ * @cs: Charset id.
+ *
+ * Expands to nonzero when characters are represented with 4byte words.
+ **/
+#define enca_charset_is_32bit(cs) \
+ (enca_charset_properties(cs) & ENCA_CHARSET_32BIT)
+
+/**
+ * enca_charset_is_fixed:
+ * @cs: Charset id.
+ *
+ * Expands to nonzero when one characters consists of one fundamental piece.
+ **/
+#define enca_charset_is_fixed(cs) \
+ (enca_charset_properties(cs) & ENCA_CHARSET_FIXED)
+
+/**
+ * enca_charset_is_variable:
+ * @cs: Charset id.
+ *
+ * Expands to nonzero when one character consists of variable number of
+ * fundamental pieces.
+ **/
+#define enca_charset_is_variable(cs) \
+ (enca_charset_properties(cs) & ENCA_CHARSET_VARIABLE)
+
+/**
+ * enca_charset_is_binary:
+ * @cs: Charset id.
+ *
+ * Expands to nonzero when charset is binary from ASCII viewpoint.
+ **/
+#define enca_charset_is_binary(cs) \
+ (enca_charset_properties(cs) & ENCA_CHARSET_BINARY)
+
+/**
+ * enca_charset_is_regular:
+ * @cs: Charset id.
+ *
+ * Expands to nonzero when charset is language dependent (8bit) charset.
+ **/
+#define enca_charset_is_regular(cs) \
+ (enca_charset_properties(cs) & ENCA_CHARSET_REGULAR)
+
+/**
+ * enca_charset_is_multibyte:
+ * @cs: Charset id.
+ *
+ * Expands to nonzero when charset is multibyte.
+ **/
+#define enca_charset_is_multibyte(cs) \
+ (enca_charset_properties(cs) & ENCA_CHARSET_MULTIBYTE)
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif
diff --git a/src/fs.c b/src/fs.c
new file mode 100644
index 0000000..6acb05b
--- /dev/null
+++ b/src/fs.c
@@ -0,0 +1,172 @@
+#include <stdio.h>
+#include <errno.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <mntent.h>
+
+#include "librcc.h"
+
+static char *rccCreateFullName(const char *path, const char *filename) {
+ unsigned int i;
+ char *name;
+
+ if (!path) {
+ if (filename) return strdup(filename);
+ else return strdup("/");
+ } else if (!filename) return strdup(path);
+
+
+ i = strlen(path);
+ name = (char*)malloc(i+strlen(filename)+2)*sizeof(char));
+ if (!name) return NULL;
+
+ if ((path[i-1]=='/')||(filename[0]=='/'))
+ sprintf(name, "%s%s", path, filename);
+ else
+ sprintf(name, "%s/%s", path, filename);
+
+ return name;
+}
+
+static int rccIsFile(const char *filename) {
+ struct stat st;
+
+ stat(filename,&st);
+ if (S_ISREG(st.st_mode)) return 1;
+ return 0;
+}
+
+static char *rccCheckFile(const char *prefix, const char *name) {
+ char *temp;
+
+ temp = rccCreateFullName(prefix, name);
+ if ((!temp)||(rccIsFile(temp))) return temp;
+
+ free(temp);
+ return NULL;
+}
+
+int rccFS0(const char *fspath, const char *filename, char **prefix, char **name) {
+ FILE *mtab;
+ struct mntent *fsentry;
+ char *tmp;
+
+ if (fspath) {
+ tmp = strstr(filename, fspath);
+ if (tmp) tmp = filename + strlen(fspath);
+ } else {
+ mtab = setmntent(_PATH_MNTTAB, "r");
+ if (mtab) {
+ while (!feof(mtab)) {
+ fsentry = getmntent(mtab);
+ if ((fsentry)&&(fsentry->mnt_dir)) {
+ tmp = strstr(filename, fsentry->mnt_dir);
+ if (tmp) tmp = filename + strlen(fsentry->mnt_dir);
+ }
+ }
+ endmntent(mtab);
+ }
+ }
+
+ if (!tmp) tmp = filename;
+
+ *name = strdup(tmp);
+ *prefix = strndup(filename, (tmp-filename));
+
+ if ((!*name)||(!*prefix)) {
+ if (*name) free(*name);
+ if (*prefix) free(*prefix);
+ return -1;
+ }
+
+ return 0;
+}
+
+int rccFS1(rcc_context *ctx, const char *fspath, char **prefix, char **name) {
+ int prefix_size;
+ char *result, *tmp;
+ char *path, *filename;
+
+ path = *prefix;
+ filename = *name;
+
+
+ if ((path)&&(filename)) {
+ result = rccCreateFullName(path, filename);
+ if (!result) return -1;
+ } else if (filename) result = filename;
+ else if (path) result = path;
+ else return -1;
+
+
+ // Checking without recoding in case of autodetection
+ if (rccGetOption(ctx, RCC_AUTODETECT_FS_NAMES)) {
+ if (rccIsFile(name)) {
+ if ((path)&&(filename)) *name = result;
+ else if (filename) *name = strdup(filename);
+ else *name = strdup(path);
+ return 1;
+ }
+ }
+
+ err = rccFS0(fspath, result, &prefix, &name);
+ if ((path)&&(filename)) free(name);
+
+ return err;
+}
+
+char *rccFS2(rcc_context *ctx, iconv_t icnv, const char *prefix, const char *name) {
+ if (icnv == (iconv_t)-1) return NULL;
+ if (icnv == (iconv_t)-2) {
+ strcpy(ctx->tmpbuffer, name);
+ ctx->tmpbuffer[len] = 0;
+ } else {
+ err = rccIConv(ctx, icnv, name, 0);
+ if (err<=0) return NULL;
+ }
+
+ return rccCheckFile(prefix, ctx->tmpbuffer);
+}
+
+char *rccFS3(rcc_context *ctx, rcc_language_id language_id, rcc_class_id class_id, const char *prefix, const char *name) {
+ rcc_charset charset;
+ rcc_language *language;
+ iconv_t icnv = ctx->fsiconv;
+
+ if ((rccGetOption(ctx, RCC_AUTODETECT_FS_NAMES))&&(icnv != (iconv_t)-1)) {
+ result = rccFS2(ctx, icnv, prefix, name);
+ if (result) return result;
+ }
+
+ result = rccFS2(ctx, ctx->iconv_to[class_id], prefix, name);
+ if (result) {
+ if ((icnv != (iconv_t)-1)||(icnv != (iconv_t)-2)) iconv_close(icnv);
+ ctx->fsiconv = (iconv_t)-1;
+ return result;
+ }
+
+ if (rccGetOption(ctx, RCC_AUTODETECT_FS_NAMES)) {
+ language = ctx->language[language_id];
+ if (language->charset[0]) {
+ for (i=1;(!result);i++) {
+ charset = language->charsets[i];
+ if (!charset) break;
+
+ if ((icnv != (iconv_t)-1)&&(icnv != (iconv_t)-2)) iconv_close(icnv);
+
+ if (strcmp(charset, "UTF-8")&&strcmp(charset, "UTF8")) icnv = (iconv_t)-2;
+ else icnv = iconv_open(charset, "UTF-8");
+
+ result = rccFS2(ctx, icnv, prefix, name);
+ }
+ }
+ }
+ if (result) ctx->fsiconv = icnv;
+ else {
+ if ((icnv != (iconv_t)-1)&&(icnv != (iconv_t)-2)) iconv_close(icnv);
+ ctx->fsiconv = (iconv_t)-1;
+ }
+
+ return result;
+}
diff --git a/src/fs.h b/src/fs.h
new file mode 100644
index 0000000..5e31507
--- /dev/null
+++ b/src/fs.h
@@ -0,0 +1,9 @@
+#ifndef _RCC_FS_H
+#define _RCC_FS_H
+
+int rccFS0(const char *fspath, const char *filename, char **prefix, char **name);
+int rccFS1(rcc_context *ctx, const char *fspath, char **prefix, char **name);
+char *rccFS2(rcc_context *ctx, iconv_t icnv, const char *prefix, const char *name);
+char *rccFS3(rcc_context *ctx, rcc_language_id language_id, rcc_class_id class_id, const char *prefix, const char *name);
+
+#endif /* _RCC_FS_H */
diff --git a/src/librcc.c b/src/librcc.c
new file mode 100644
index 0000000..6f621fc
--- /dev/null
+++ b/src/librcc.c
@@ -0,0 +1,312 @@
+#include <stdio.h>
+#include <string.h>
+
+#include <librcd.h>
+#include "librcc.h"
+#include "enca.h"
+
+#include "config.h"
+
+int rccInit() {
+ return rccEncaInit();
+}
+
+void rccFree() {
+ rccEncaFree();
+}
+
+rcc_context rccInitContext(rcc_init_flags flags, unsigned int max_languages, unsigned int max_classes, const char *locale) {
+ unsigned int i;
+
+ rcc_context *ctx;
+ rcc_language_ptr *languages;
+ rcc_class_ptr *classes;
+ rcc_language_config *configs;
+ iconv_t *from, *to;
+
+ if (!max_languages) max_languages = RCC_MAX_LANGUAGES;
+ if (!max_classes) max_classes = RCC_MAX_CLASSES;
+
+ ctx = (rcc_context*)malloc(sizeof(rcc_context));
+ languages = (rcc_language_ptr*)malloc((max_languages+1)*sizeof(rcc_language_ptr));
+ classes = (rcc_class_ptr*)malloc((max_classes+1)*sizeof(rcc_class_ptr));
+ from = (iconv_t*)malloc((max_classes)*sizeof(iconv_t));
+ to = (iconv_t*)malloc((max_classes)*sizeof(iconv_t));
+
+ configs = (rcc_language_config*)malloc((max_languages)*sizeof(rcc_language_config));
+
+ if ((!ctx)||(!languages)||(!classes)) {
+ if (from) free(from);
+ if (to) free(to);
+ if (configs) free(configs);
+ if (classes) free(classes);
+ if (languages) free(languages);
+ if (ctx) free(ctx);
+ return NULL;
+ }
+
+ ctx->languages = languages;
+ ctx->max_languages = max_languages;
+ ctx->n_languages = 0;
+ languages[0] = NULL;
+
+ ctx->classes = classes;
+ ctx->max_classes = max_classes;
+ ctx->n_classes = 0;
+ classes[0] = NULL;
+
+ ctx->fsiconv = (iconv_t)-1;
+
+ ctx->iconv_from = from;
+ ctx->iconv_to = to;
+ for (i=0;i<max_classes;i++) {
+ from[i] = (iconv_t)-1;
+ to[i] = (iconv_t)-1;
+ }
+
+ for (i=0;i<RCC_MAX_CHARSETS;i++)
+ ctx->iconv_auto[i] = (iconv_t)-1;
+
+ ctx->configs = configs;
+ for (i=0;i<max_languages;i++)
+ configs[i].charset = NULL;
+
+ err = rccEngineInit(&ctx->engine_ctx, ctx);
+ if (err) {
+ rccFree(ctx);
+ return NULL;
+ }
+
+ ctx->current_language = 0;
+
+ if (locale) {
+ if (strlen(locale)>=RCC_MAX_VARIABLE_CHARS) {
+ rccFree(ctx);
+ return NULL;
+ }
+ strcpy(ctx->locale_variable, locale);
+ } else {
+ strcpy(ctx->locale_variable, RCC_LOCALE_VARIABLE);
+ }
+
+ if (flags&RCC_DEFAULT_CONFIGURATION) {
+ if (sizeof(languages)<sizeof(rcc_default_languages)) {
+ rccFree(ctx);
+ return NULL;
+ }
+
+ for (i=0;rcc_default_languages[i];i++)
+ rccRegisterLanguage(ctx, rcc_default_language[i]);
+
+ ctx->current_config = rccGetCurrentConfig(ctx);
+ } else {
+ rccRegisterLanguage(ctx, rcc_default_language[0]);
+ ctx->current_config = NULL;
+ }
+
+ ctx->configure = 1;
+
+ return ctx;
+}
+
+static void rccFreeIConv(rcc_context *ctx) {
+ unsigned int i;
+
+ if ((!ctx)||(!ctx->iconv_from)||(!ctx->iconv_to)) return;
+
+ if ((ctx->fsiconv_t != (iconv_t)-1)&&(ctx->fsiconv_t != (iconv_t)-2)) {
+ iconv_close(ctx->fsiconv);
+ ctx->fsiconv = (iconv_t)-1;
+ }
+
+ for (i=0;i<ctx->n_classes;i++) {
+ if ((ctx->iconv_from[i] != (iconv_t)-1)&&(ctx->iconv_from[i] != (iconv_t)-2)) {
+ iconv_close(ctx->iconv_from[i]);
+ ctx->iconv_from[i] = (iconv_t)-1;
+ }
+ if ((ctx->iconv_to[i] != (iconv_t)-1)&&(ctx->iconv_to[i] != (iconv_t)-2)) {
+ iconv_close(ctx->iconv_to[i]);
+ ctx->iconv_to[i] = (iconv_t)-1;
+ }
+ }
+ for (i=0;i<RCC_MAX_CHARSETS;i++) {
+ if ((ctx->iconv_auto[i] != (iconv_t)-1)&&(ctx->iconv_auto[i] != (iconv_t)-2)) {
+ iconv_close(ctx->iconv_auto[i]);
+ ctx->iconv_auto[i] = (iconv_t)-1;
+ }
+ }
+}
+
+void rccFreeContext(rcc_context *ctx) {
+ if (ctx) {
+ rccFreeEngine(&ctx->engine_ctx);
+ rccFreeIConv(ctx);
+ if (ctx->iconv_from) free(ctx->iconv_from);
+ if (ctx->iconv_to) free(ctx->iconv_to);
+
+ if (ctx->configs) {
+ for (i=0;i<ctx->max_languages;i++)
+ rccFreeConfig(configs+i);
+ free(ctx->configs);
+ }
+ if (ctx->charsets) free(ctx->charsets);
+ if (ctx->classes) free(ctx->classes);
+ if (ctx->languages) free(ctx->languages);
+ free(ctx);
+ }
+}
+
+rcc_language_id rccRegisterLanguage(rcc_context *ctx, rcc_language *language) {
+ if ((!ctx)||(!language)) return -1;
+ if (ctx->n_languages == ctx->max_languages) return -2;
+ ctx->languages[ctx->n_languages++] = language;
+ ctx->languages[ctx->n_languages] = NULL;
+
+ if (!ctx->current_language)
+ ctx->current_config = rccGetCurrentConfig(ctx);
+
+ return ctx->n_languages-1;
+}
+
+rcc_charset_id rccLanguageRegisterCharset(rcc_language *language, rcc_charset charset) {
+ unsigned int i;
+
+ if ((!language)||(!charset)) return -1;
+ for (i=0;language->charsets[i];i++);
+ if (i>=RCC_MAX_CHARSETS) return -2;
+ language->charsets[i++] = charset;
+ language->charsets[i] = NULL;
+ return i-1;
+}
+
+rcc_engine_id rccLanguageRegisterEngine(rcc_language *language, rcc_engine *engine) {
+ unsigned int i;
+
+ if ((!language)||(!engine)) return -1;
+ for (i=0;language->engines[i];i++);
+ if (i>=RCC_MAX_ENGINES) return -2;
+ language->engines[i++] = engine;
+ language->engines[i] = NULL;
+ return i-1;
+}
+
+rcc_class_id rccRegisterClass(rcc_context *ctx, rcc_class *cl) {
+ if ((!ctx)||(!cl)) return -1;
+ if (ctx->n_classes == ctx->max_classes) return -2;
+ ctx->configure = 1;
+ ctx->classes[ctx->n_languages++] = cl;
+ ctx->classes[ctx->n_languages] = NULL;
+ return ctx->n_classes-1;
+}
+
+
+rcc_class_type rccGetClassType(rcc_context *ctx, rcc_class_id class_id) {
+ rcc_class cl;
+
+ if (!ctx)||(class_id<0)||(class_id>=ctx->n_classes)) return RCC_CLASS_INVALID;
+
+ cl = rcc->classes[class_id];
+ return cl->class_type;
+}
+
+static rcc_language *rccGetLanguageList(rcc_context *ctx) {
+ if (!ctx) return NULL;
+ return ctx->languages;
+}
+
+static rcc_charset *rccGetCharsetList(rcc_context *ctx, rcc_language_id language_id) {
+ if ((!ctx)||(language_id<0)||(language_id>=ctx->n_languages)) return NULL;
+ return ctx->languages[language_id]->charsets;
+}
+
+static rcc_engine *rccGetEngineList(rcc_context *ctx, rcc_language_id language_id) {
+ if ((!ctx)||(language_id<0)||(language_id>=ctx->n_languages)) return NULL;
+ return ctx->languages[language_id]->engines;
+}
+
+static rcc_charset *rccGetCurrentCharsetList(rcc_context *ctx) {
+ rcc_language_id language_id;
+
+ if (!ctx) return NULL;
+
+ language_id = rccGetCurrentLanguage(ctx);
+ if (language_id<0) return NULL;
+
+ return rccGetCharsetList(ctx, language_id);
+}
+
+static rcc_charset *rccGetCurrentEngineList(rcc_context *ctx) {
+ rcc_language_id language_id;
+
+ if (!ctx) return NULL;
+
+ language_id = rccGetCurrentLanguage(ctx);
+ if (language_id<0) return NULL;
+
+ return rccGetEngineList(ctx, language_id);
+}
+
+static rcc_charset *rccGetCurrentAutoCharsetList(rcc_context *ctx) {
+ rcc_language_id language_id;
+ rcc_engine_id engine_id;
+
+ if (!ctx) return NULL;
+
+ language_id = rccGetCurrentLanguage(ctx);
+ engine_id = rccGetCurrentEngine(ctx);
+ if ((language_id<0)||(engine_id<0)) return NULL;
+
+
+ return ctx->languages[language_id]->engine[engine_id]->charsets;
+}
+
+
+int rccConfigure(rcc_engine_context *ctx) {
+ unsigned int i;
+ rcc_charset *charsets;
+ char *charset;
+
+ if (!ctx) return -1;
+ if (!ctx->configure) return 0;
+
+ rccFreeIConv(ctx);
+ for (i=0;i<ctx->n_classes;i++) {
+ charset = rccGetCurrentCharsetName(ctx, i);
+ if (strcmp(charset, "UTF-8")&&strcmp(charset, "UTF8")) {
+ iconv_from = iconv_open("UTF-8", charset);
+ iconv_to = iconv_open(charset, "UTF-8");
+ } else {
+ iconv_from = (iconv_t)-2;
+ iconv_to = (iconv_t)-2;
+ }
+ }
+
+ charsets = rccGetCurrentAutoCharsetList(ctx);
+ for (i=0;charsets[i];i++) {
+ charset = charsets[i];
+ if (strcmp(charset, "UTF-8")&&strcmp(charset, "UTF8"))
+ iconv_auto = iconv_open("UTF-8", charset);
+ else
+ iconv_auto = (iconv_t)-2;
+ }
+
+ rccEngineConfigure(&ctx->engine_ctx);
+
+ return 0;
+}
+
+char *rccCreateResult(rcc_context *ctx, int len, int *rlen) {
+ char *res;
+
+ if (!len) len = strlen(ctx->tmpbuffer);
+
+ res = (char*)malloc(len+1);
+ if (!res) return NULL;
+
+ memcpy(res, ctx->tmpbuffer, len);
+ res[len] = 0;
+
+ if (rlen) *rlen = len;
+
+ return res;
+}
diff --git a/src/librcc.h b/src/librcc.h
new file mode 100644
index 0000000..c3d6f17
--- /dev/null
+++ b/src/librcc.h
@@ -0,0 +1,271 @@
+#ifndef LIBRCC_H
+#define LIBRCC_H
+
+#include <iconv.h>
+
+#define RCC_MAX_CHARSETS 16
+#define RCC_MAX_ENGINES 5
+#define RCC_MAX_LANGUAGES 64
+#define RCC_MAX_CLASSES 16
+
+#define RCC_MAX_ERRORS 3
+
+#define RCC_MAX_CHARSET_CHARS 16
+#define RCC_MAX_LANGUAGE_CHARS 16
+#define RCC_MAX_VARIABLE_CHARS 16
+
+#define RCC_MAX_STRING_CHARS 1024
+
+#define RCC_STRING_MAGIC 0xFF7F01FF
+/*
+ class = charset class
+ engine = auto engine
+ selected - which is selected
+ current - resolves default values
+*/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef unsigned int rcc_init_flags;
+#define RCC_DEFAULT_CONFIGURATION 1
+
+typedef int rcc_option_value;
+typedef enum rcc_option_t {
+ RCC_LEARNING_MODE = 0,
+ RCC_AUTODETECT_FS_TITLES,
+ RCC_AUTODETECT_FS_NAMES,
+ RCC_USE_HEADERS,
+ RCC_MAX_OPTIONS
+} rcc_option;
+
+typedef enum rcc_class_type_t {
+ RCC_CLASS_INVALID = 0,
+ RCC_CLASS_STANDARD,
+ RCC_CLASS_FS
+} rcc_class_type;
+
+
+struct rcc_string_header_t {
+ unsigned int magic;
+ rcc_language_id language_id;
+};
+typedef struct rcc_string_header_t rcc_string_header;
+
+typedef char *rcc_string;
+typedef char rcc_language_id;
+typedef char rcc_charset_id;
+typedef char rcc_engine_id;
+typedef int rcc_class_id;
+
+typedef struct rcc_context_t rcc_context;
+typedef struct rcc_engine_context_t rcc_engine_ctx;
+typedef const struct rcc_class_t rcc_class;
+typedef struct rcc_language_t rcc_language;
+typedef struct rcc_engine_t rcc_engine;
+typedef const char *rcc_charset;
+
+typedef struct rcc_language_config_t rcc_language_config;
+typedef const struct rcc_language_alias_t rcc_language_alias;
+
+typedef void *rcc_engine_internal;
+typedef rcc_engine_internal (*rcc_engine_init_function)(rcc_engine_context *ctx);
+typedef rcc_charset_id (*rcc_engine_function)(rcc_engine_context ctx, char *buf, int len);
+typedef void (rcc_engine_free_function)(rcc_engine_context ctx);
+
+typedef rcc_charset rcc_charset_list[RCC_MAX_CHARSETS+1];
+
+struct rcc_engine_t {
+ const char *title;
+ rcc_engine_init_function init_func;
+ rcc_engine_free_function free_func;
+ rcc_engine_function func;
+ rcc_charset_list charsets;
+};
+typedef rcc_engine *rcc_engine_ptr;
+typedef rcc_engine_ptr rcc_engine_list[RCC_MAX_ENGINES+1];
+
+struct rcc_language_t {
+ const char *sn;
+ const char *name;
+ rcc_charset_list charsets;
+ rcc_engine_list engines;
+};
+typedef rcc_language *rcc_language_ptr;
+typedef rcc_language_ptr rcc_language_list[RCC_MAX_LANGUAGES+1];
+
+struct rcc_language_alias_t {
+ const char *alias;
+ const char *lang;
+};
+
+struct rcc_class_t {
+ const char *name;
+ const char *defvalue; /* locale variable name or parrent name */
+ const rcc_class_type class_type;
+};
+typedef rcc_class *rcc_class_ptr;
+typedef rcc_class_ptr rcc_class_list[RCC_MAX_CLASSES+1];
+
+struct rcc_language_config_t {
+ rcc_context *ctx;
+ rcc_language *language;
+
+ rcc_engine_id engine;
+ rcc_charset_id *charset;
+ rcc_option_value options[RCC_MAX_OPTIONS];
+};
+
+struct rcc_engine_context_t {
+ rcc_context *ctx;
+ rcc_language *language;
+
+ rcc_engine_function func;
+ rcc_engine_free_function free_func;
+
+ rcc_engine_internal internal;
+};
+
+struct rcc_context_t {
+ char locale_variable[RCC_MAX_VARIABLE_CHARS+1];
+
+ unsigned int max_languages;
+ unsigned int n_languages;
+ rcc_language_ptr *languages;
+ rcc_language_config *configs;
+
+ unsigned int max_classes;
+ unsigned int n_classes;
+ rcc_class_ptr *classes;
+
+ rcc_engine_ctx engine_ctx;
+
+ iconv_t *iconv_from;
+ iconv_t *iconv_to;
+ iconv_t iconv_auto[RCC_MAX_CHARSETS];
+
+ char tmpbuffer[RCC_MAX_STRING_CHARS+sizeof(rcc_string_footer)+1];
+ iconv_t fsiconv;
+
+ unsigned char configure;
+ rcc_language_config *current_config;
+ rcc_language_id current_language;
+};
+
+int rccInit();
+void rccFree();
+
+rcc_context rccInitContext(rcc_init_flags flags, unsigned int max_languages, unsigned int max_classes, const char *locale);
+void rccFreeContext(rcc_context *ctx);
+
+rcc_language_id rccRegisterLanguage(rcc_context *ctx, rcc_language *language);
+rcc_charset_id rccLanguageRegisterCharset(rcc_language *language, rcc_charset charset);
+rcc_engine_id rccLanguageRegisterEngine(rcc_language *language, rcc_engine *engine);
+rcc_class_id rccRegisterClass(rcc_context *ctx, rcc_class *cl);
+
+rcc_class_type rccGetClassType(rcc_context *ctx, rcc_class_id class_id);
+
+int rccConfigure(rcc_context *ctx);
+char *rccCreateResult(rcc_context *ctx, int len, int *rlen);
+
+/* lng.c */
+const char *rccGetLanguageName(rcc_context *ctx, rcc_language_id language_id);
+rcc_language_id rccGetLanguageByName(rcc_context *ctx, const char *name);
+rcc_language_id rccGetRealLanguage(rcc_context *ctx, rcc_language_id language_id);
+const char *rccGetRealLanguageName(rcc_context *ctx, rcc_language_id language_id);
+rcc_language_id rccGetSelectedLanguage(rcc_context *ctx);
+const char *rccGetSelectedLanguageName(rcc_context *ctx);
+rcc_language_id rccGetCurrentLanguage(rcc_context *ctx);
+const char *rccGetCurrentLanguageName(rcc_context *ctx);
+
+int rccSetLanguage(rcc_context *ctx, rcc_language_id language_id);
+int rccSetLanguageByName(rcc_context *ctx, const char *name);
+
+/* lngconfig.c */
+int rccConfigInit(rcc_language_config *config, rcc_context *ctx);
+int rccConfigFree(rcc_language_config *config);
+
+const char *rccConfigGetEngineName(rcc_language_config config, rcc_engine_id engine_id);
+const char *rccConfigGetCharsetName(rcc_language_config config, rcc_charset_id charset_id);
+const char *rccConfigGetAutoCharsetName(rcc_language_config config, rcc_charset_id charset_id);
+rcc_engine_id rccConfigGetEngineByName(rcc_language_config *config, const char *name);
+rcc_charset_id rccConfigGetCharsetByName(rcc_language_config *config, const char *name);
+rcc_charset_id rccConfigGetAutoCharsetByName(rcc_language_config *config, const char *name);
+
+rcc_language_config *rccGetConfig(rcc_context *ctx, rcc_language_id language_id);
+rcc_language_config *rccGetConfigByName(rcc_context *ctx, const char *name);
+rcc_language_config *rccGetCurrentConfig(rcc_context *ctx);
+
+rcc_engine_id rccConfigGetSelectedEngine(rcc_language_config config);
+const char *rccConfigGetSelectedEngineName(rcc_language_config config);
+rcc_engine_id rccConfigGetCurrentEngine(rcc_language_config config);
+const char *rccConfigGetCurrentEngineName(rcc_language_config config);
+rcc_charset_id rccConfigGetSelectedCharset(rcc_language_config config, rcc_class_id class_id);
+const char *rccConfigGetSelectedCharsetName(rcc_language_config config, rcc_class_id class_id);
+rcc_charset_id rccConfigGetCurrentCharset(rcc_language_config config, rcc_class_id class_id);
+const char *rccConfigGetCurrentCharsetName(rcc_language_config config, rcc_class_id class_id);
+rcc_option_value rccConfigGetOption(rcc_language_config config, rcc_option option);
+
+int rccConfigSetEngine(rcc_language_config *config, rcc_engine_id engine_id);
+int rccConfigSetCharset(rcc_language_config *config, rcc_class_id class_id, rcc_charset_id charset_id);
+int rccConfigSetEngineByName(rcc_language_config *config, const char *name);
+int rccConfigSetCharsetByName(rcc_language_config *config, rcc_class_id class_id, const char *name);
+int rccConfigSetOption(rcc_language_config *config, rcc_option option, rcc_option_value value);
+
+rcc_charset_id rccConfigGetLocaleCharset(rcc_language_config *config, const char *locale_variable);
+
+/* curconfig.c */
+#define rccGetEngineName(ctx, engine_id) rccConfigGetEngineName(ctx->current_config, engine_id)
+#define rccGetCharsetName(ctx, charset_id) rccConfigGetCharsetName(ctx->current_config, charset_id)
+#define rccGetAutoCharsetName(ctx, charset_id) rccConfGetAutoCharsetName(ctx->current_config, charset_id)
+#define rccGetEngineByName(ctx, name) rccConfigGetEngineByName(ctx->current_config, name)
+#define rccGetCharsetByName(ctx, name) rccConfigGetCharsetByName(ctx->current_config, name)
+#define rccGetAutoCharsetByName(ctx, name) rccConfigGetAutoCharsetByName(ctx->current_config, name)
+
+#define rccGetSelectedEngine(ctx) rccConfigGetSelectedEngine(ctx->current_config)
+#define rccGetSelectedEngineName(ctx) rccConfigGetSelectedEngineName(ctx->current_config)
+#define rccGetCurrentEngine(ctx) rccConfigGetCurrentEngine(ctx->current_config)
+#define rccGetCurrentEngineName(ctx) rccConfigGetCurrentEngineName(ctx->current_config)
+#define rccGetSelectedCharset(ctx,class_id) rccConfigGetSelectedCharset(ctx->current_config, class_id)
+#define rccGetSelectedCharsetName(ctx,class_id) rccConfigGetSelectedCharsetName(ctx->current_config, class_id)
+#define rccGetCurrentCharset(ctx,class_id) rccConfigGetCurrentCharset(ctx->current_config, class_id)
+#define rccGetCurrentCharsetName(ctx,class_id) rccConfigGetCurrentCharsetName(ctx->current_config, class_id)
+#define rccGetOption(ctx, option) rccConfigGetOption(ctx->current_config, option)
+
+#define rccSetEngine(ctx, engine_id) rccConfigSetEngine(ctx->current_config, engine_id)
+#define rccSetCharset(ctx, class_id, charset_id) rccConfigSetCharset(ctx->current_config, class_id, charset_id)
+#define rccSetOption(ctx,option,value) rccConfigSetOption(ctx->current_config, option, value)
+#define rccSetEngineByName(ctx, name) rccConfigSetEngineByName(ctx->current_config, name)
+#define rccSetCharsetByName(ctx, class_id, name) rccConfigSetCharsetByName(ctx->current_config, class_id, name)
+
+#define rccGetLocaleCharset(ctx, locale_variable) rccConfigGetLocaleCharset(ctx->current_config, locale_variable)
+
+/* recode.c */
+char *rccFrom(rcc_context *ctx, rcc_class_id class_id, char *buf, int len, int *rlen);
+char *rccTo(rcc_context *ctx, rcc_class_id class_id, char *buf, int len, int *rlen);
+char *rccRecode(rcc_context *ctx, rcc_class_id from, rcc_class_id to, char *buf, int len, int *rlen);
+char *rccFS(rcc_context *ctx, char *fspath, char *path, char *filename, int len, int *rlen);
+
+/* string.c */
+rcc_string rccStringInit(rcc_language_id language_id, const char *buf, int len, int *rlen);
+void rccStringFree(rcc_string str);
+
+rcc_language_id rccStringCheck(const rcc_string str);
+const char *rccStringGet(const rcc_string str);
+char *rccStringExtract(const rcc_string buf, int len, int *rlen);
+
+char *rccStringCmp(const rcc_string str1, const rcc_string str2);
+char *rccStringNCmp(const rcc_string str1, const rcc_string str2, size_t n);
+char *rccStringCaseCmp(const rcc_string str1, const rcc_string str2);
+char *rccStringNCaseCmp(const rcc_string str1, const rcc_string str2, size_t n);
+
+/* xml.c */
+int rccSave(rcc_context *ctx);
+int rccLoad(rcc_context *ctx);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* LIBRCC_H */
diff --git a/src/lng.c b/src/lng.c
new file mode 100644
index 0000000..607c69d
--- /dev/null
+++ b/src/lng.c
@@ -0,0 +1,135 @@
+#include <stdio.h>
+#include <string.h>
+#include <locale.h>
+
+#include <librcd.h>
+#include "librcc.h"
+
+const char *rccGetLanguageName(rcc_context *ctx, rcc_language_id language_id) {
+ if ((!ctx)||(language_id<0)||(language_id>=ctx->n_languages)) return NULL;
+ return ctx->languages[language_id]->sn;
+}
+
+language_id rccGetLanguageByName(rcc_context *ctx, const char *name) {
+ unsigned int i;
+ if ((!ctx)||(!name)) return 0;
+
+ for (i=0;ctx->languages[i];i++)
+ if (!strcmp(ctx->languages[i]->sn, name)) return i;
+
+ return 0;
+}
+
+static int rccGetLocaleLanguage(char *result, const char *lv, unsigned int n) {
+ charset_list_t *enc;
+ char *l;
+
+ if (!lv) return -1;
+
+ l = setlocale(lv, NULL);
+ if (!l) return -1;
+ else if ((strcmp(l,"C")==0)||(strcmp(l,"POSIX")==0)) return -1;
+
+ for (i=0;((l[i])&&(l[i]!='.'));i++);
+
+ for (i=0;rcc_default_aliases[i].alias;i++)
+ if (strncmp(l,rcc_default_aliases[i].alias,i)==0) {
+ l = rcc_default_aliases[i].alias;
+ break;
+ }
+
+ for (i=0;((l[i])&&(l[i]!='.')&&(l[i]!='_'));i++);
+ if (i>=n) return -1;
+
+ strncpy(result,l,i);
+ result[i]=0;
+
+ return 0;
+}
+
+static rcc_language_id rccGetDefaultLanguage(rc_context *ctx) {
+ int err;
+ unsigned int i;
+ char stmp[RCC_MAX_LANGUAGE_CHARS+1];
+
+ if (!ctx) return -1;
+
+ err = rccGetLocaleLanguage(stmp, ctx->locale_variable, RCC_MAX_LANGUAGE_CHARS);
+ if (err) {
+ if (ctx->n_languages>1) return 1;
+ return -1;
+ }
+
+ for (i=0;ctx->languages[i];i++)
+ if (!strcmp(ctx->languages[i]->sn, stmp)) return i;
+
+ if (i>1) return 1;
+ return -1;
+}
+
+rcc_language_id rccGetRealLanguage(rcc_context *ctx, rcc_language_id language_id) {
+ if ((!ctx)||(language_id<0)||(language_id>=ctx->n_languages)) return -1;
+ if (language_id) return language_id;
+ return rccGetDefaultLanguage(ctx);
+}
+
+const char *rccGetRealLanguageName(rcc_context *ctx, rcc_language_id language_id) {
+ language_id = rccGetRealLanguage(ctx, language_id);
+ if (language_id<0) return NULL;
+
+ return rccGetLanguageName(ctx, language_id);
+}
+
+rcc_language_id rccGetSelectedLanguage(rcc_context *ctx) {
+ if (!ctx) return NULL;
+ return ctx->current_language;
+}
+
+const char *rccGetSelectedLanguageName(rcc_context *ctx) {
+ rcc_language_id language_id;
+
+ language_id = rccGetSelectedLanguage(ctx);
+ if (language_id<0) return NULL;
+
+ return rccGetLanguageName(ctx, language_id);
+}
+
+rcc_language_id rccGetCurrentLanguage(rcc_context *ctx) {
+ if (!ctx) return -1;
+ return rccGetRealLanguage(ctx, ctx->current_language);
+}
+
+const char *rccGetCurrentLanguageName(rcc_context *ctx) {
+ rcc_language_id language_id;
+
+ language_id = rccGetCurrentLanguage(ctx);
+ if (language_id<0) return NULL;
+
+ return rccGetLanguageName(ctx, language_id);
+}
+
+
+int rccSetLanguage(rcc_context *ctx, rcc_language_id language_id) {
+ rcc_language_config config;
+
+ if ((!ctx)||(language_id < 0)||(language_id >= ctx->n_languages)) return -1;
+ if ((!ctx->languages[language_id]->engines[0])||(!ctx->languages[language_id]->charsets[0])) return -2;
+
+ if (ctx->current_language != language_id) {
+ config = rccGetConfig(ctx, language_id);
+ if (!config) return -1;
+
+ ctx->configure = 1;
+ ctx->current_language = language_id;
+ ctx->current_config = config;
+ }
+}
+
+int rccSetLanguageByName(rcc_context *ctx, const char *name) {
+ rcc_language_id language_id;
+
+ language_id = rccGetLanguageByName(ctx, name);
+ if (language_id < 0) return -1;
+
+ return rccSetLanguage(ctx, language_id);
+}
diff --git a/src/lngconfig.c b/src/lngconfig.c
new file mode 100644
index 0000000..ba904ec
--- /dev/null
+++ b/src/lngconfig.c
@@ -0,0 +1,363 @@
+#include <stdio.h>
+#include <string.h>
+
+#include <librcd.h>
+#include "librcc.h"
+#include "config.h"
+
+const char *rccConfigGetEngineName(rcc_language_config config, rcc_engine_id engine_id) {
+ rcc_engine_ptr *engines;
+
+ if ((!config)||(!config->language)||(engine_id<0)) return NULL;
+
+ engines = config->language->engines;
+
+ for (i=0;engines[i];i++);
+ if (engine_id>=i) return NULL;
+
+ return engines[engine_id]->title;
+}
+
+const char *rccConfigGetCharsetName(rcc_language_config config, rcc_charset_id charset_id) {
+ rcc_charset_ptr *charsets;
+
+ if ((!config)||(!config->language)||(charset_id<0)) return NULL;
+
+ charsets = config->language->charsets;
+
+ for (i=0;charsets[i];i++);
+ if (charset_id>=i) return NULL;
+
+ return charsets[charset_id];
+}
+
+const char *rccConfigGetAutoCharsetName(rcc_language_config config, rcc_charset_id charset_id) {
+ rcc_charset_ptr *charsets;
+ rcc_engine_ptr *engines;
+
+ if ((!config)||(!config->language)||(engine_id<0)) return NULL;
+
+ engines = config->language->engines;
+ charsets = engines[config->engine]->charsets;
+
+ for (i=0;charsets[i];i++);
+ if (charset_id>=i) return NULL;
+
+ return charsets[charset_id];
+}
+
+
+rcc_engine_id rccConfigGetEngineByName(rcc_language_config *config, const char *name) {
+ unsigned int i;
+ rcc_engine *engines;
+
+ if ((!config)||(!config->language)||(!name)) return -1;
+
+ engines = config->language->engines;
+ for (i=0;engines[i];i++)
+ if (!strcmp(engines[i]->title,name)) return i;
+
+ return -1;
+}
+
+rcc_charset_id rccConfigGetCharsetByName(rcc_language_config *config, const char *name) {
+ unsigned int i;
+ rcc_charset *charsets;
+
+ if ((!config)||(!config->language)||(!name)) return -1;
+
+ charsets = config->language->charsets;
+ for (i=0;charsets[i];i++)
+ if (!strcmp(charsets[i],name)) return i;
+
+ return 0;
+}
+
+rcc_charset_id rccConfigGetAutoCharsetByName(rcc_language_config *config, const char *name) {
+ unsigned int i;
+ rcc_charset *charsets;
+ rcc_engine_ptr *engines;
+
+ if ((!config)||(!config->language)||(!name)) return -1;
+
+ engines = config->language->engines;
+ charsets = engines[config->engine]->charsets;
+
+ for (i=0;charsets[i];i++)
+ if (!strcmp(charsets[i],name)) return i;
+
+ return -1;
+}
+
+int rccConfigInit(rcc_language_config *config, rcc_context *ctx) {
+ rcc_charset_id *charsets;
+
+ if ((!ctx)||(!config)) return -1;
+
+ charsets = (rcc_charset_id*)malloc((ctx->max_classes)*sizeof(rcc_charset_id));
+ if (!charsets) return -1;
+
+ for (i=0;i<ctx->max_classes;i++)
+ charsets[i] = 0;
+
+ config->ctx = ctx;
+ config->language = NULL;
+ config->charset = charsets;
+ config->engine = -1;
+ for (i=0;i<RCC_MAX_OPTIONS;i++)
+ config->options[i] = 0;
+
+ return 0;
+}
+
+int rccConfigFree(rcc_language_config *config) {
+ if (config->charset) {
+ free(config->charset);
+ config->charset = NULL;
+ }
+}
+
+
+rcc_language_config *rccGetConfig(rcc_context *ctx, rcc_language_id language_id) {
+ int err;
+
+ language_id = rccGetRealLanguage(ctx, language_id);
+ if (language_id < 0) return NULL;
+ if (!ctx->configs[language_id].charsets) {
+ if (rccInitConfig(ctx->configs+language_id, ctx)) return NULL;
+ }
+
+ ctx->configs[language_id] = ctx->languages[language_id];
+ return ctx->configs + language_id;
+}
+
+rcc_language_config *rccGetConfigByName(rcc_context *ctx, const char *name) {
+ rcc_language_id language_id;
+
+ language_id = rccGetLanguageByName(ctx, name);
+ if (language_id < 0) return NULL;
+
+ return rccGetConfig(ctx, language_id);
+}
+
+rcc_language_config *rccGetCurrentConfig(rcc_context *ctx) {
+ rcc_language_id language_id;
+
+ language_id = rccGetCurrentLanguage(ctx);
+ if (language_id < 0) return NULL;
+
+ return rccGetConfig(ctx, language_id);
+}
+
+
+rcc_engine_id rccConfigGetSelectedEngine(rcc_language_config config) {
+ if (!config) return -1;
+
+ return config->engine;
+}
+
+const char *rccConfigGetSelectedEngineName(rcc_language_config config) {
+ rcc_engine_id engine_id;
+
+ engine_id = rccConfigGetSelectedEngine(config);
+ if (engine_id == -1) return rcc_engine_nonconfigured;
+ if ((engine_id < 0)||(!config->language)) return NULL;
+
+ return rccConfigGetEngineName(config, engine_id);
+}
+
+rcc_engine_id rccConfigGetCurrentEngine(rcc_language_config config) {
+ rcc_engine_list enginelist;
+ rcc_engine_id engine_id;
+
+ engine_id = rccConfigGetSelectedEngine(config);
+ if (engine_id>=0) return engine_id;
+
+ if (!config->language) return NULL;
+ else enginelist = config->language->engines;
+
+ if (enginelist[0]) {
+ if (enginelist[1]) return 1;
+ return 0;
+ }
+ return -1;
+}
+
+const char *rccConfigGetCurrentEngineName(rcc_language_config config) {
+ rcc_engine_id engine_id;
+
+ engine_id = rccConfigGetCurrentEngine(config);
+ if ((engine_id < 0)||(!config->language)) return NULL;
+
+ return rccConfigGetEngineName(config, engine_id);
+}
+
+
+static int rccGetLocaleCharset(char *result, const char *lv, unsigned int n) {
+ char *l;
+
+ if (!lv) return -1;
+ l = setlocale(lv, NULL);
+ if (!l) return -1;
+
+ for (i=0;((l[i])&&(l[i]!='.')&&(l[i]!='_'));i++);
+ if (i>=n) return -1;
+
+ l = strrchr(l, '.');
+ if (!l) return -1;
+
+ for (i=0;((l[i])&&(l[i]!='@'));i++);
+ if (i>=n) return -1;
+
+ strncpy(result,l,i);
+ result[i]=0;
+
+ return 0;
+}
+
+rcc_charset_id rccConfigGetSelectedCharset(rcc_language_config config, rcc_class_id class_id) {
+ if ((!config)||(!config->ctx)||(class_id<0)||(class_id>=ctx->n_classes)) return -1;
+
+ return config->charset[class_id];
+}
+
+const char *rccConfigGetSelectedCharsetName(rcc_language_config config, rcc_class_id class_id) {
+ rcc_charset_id charset_id;
+
+ charset_id = rccConfigGetSelectedCharset(config, class_id);
+ if ((charset_id < 0)||(!config->language)) return NULL;
+
+ return rccConfigGetCharsetName(config, charset_id);
+}
+
+rcc_charset_id rccConfigGetCurrentCharset(rcc_language_config config, rcc_class_id class_id) {
+ int err;
+ unsigned int i;
+ rcc_charset_id charset_id;
+
+ rcc_language *language;
+ rcc_class *classes;
+ rcc_charset *charsets;
+
+ char stmp[RCC_MAX_CHARSET_CHARS + 1];
+ char *defvalue;
+
+ if ((!config)||(!config->ctx)||(class_id<0)||(class_id>=ctx->n_classes)) return NULL;
+
+ charset_id = ctx->config->charset[class_id];
+ if (charset_id) return charset_id;
+
+ if (!config->language) return -1;
+ else language = config->language;
+
+ classes = config->ctx->classes;
+
+ cl = classes[class_id];
+ defvalue = cl->defvalue;
+ if (defvalue) {
+ for (i=0;classes[i];i++) {
+ if (!strcmp(classes[i]->name, defvalue))
+ return rccConfigGetCurrentCharset(config, i);
+ }
+ } else defvalue = config->ctx->locale_variable;
+
+ err = rccGetLocaleCharset(stmp, defvalue, RCC_MAX_CHARSET_CHARS);
+ if (err) {
+ charsets=ctx->languages[language_id]->charsets;
+ if ((charsets[0])&&(charsets[1])) return 1;
+ return -1;
+ }
+
+ return rccConfigGetCharsetByName(config, stmp);
+}
+
+const char *rccConfigGetCurrentCharsetName(rcc_language_config config, rcc_class_id class_id) {
+ rcc_charset_id charset_id;
+
+ charset_id = rccConfigGetCurrentCharset(config, class_id);
+ if ((charset_id < 0)||(!config->language)) return NULL;
+
+ return rccConfigGetCharsetName(config, charset_id);
+}
+
+rcc_option_value rccConfigGetOption(rcc_language_config config, rcc_option option) {
+ if ((!config)||(option<0)||(option>=RCC_MAX_OPTIONS)) return -1;
+
+ return config->options[option];
+}
+
+int rccConfigSetEngine(rcc_language_config *config, rcc_engine_id engine_id) {
+ unsigned int i;
+
+ if ((!config)||(!config->language)||(engine_id < 0)) return -1;
+
+ for (i=0;config->language->engines[i];i++);
+ if (engine_id >= i) return -1;
+
+ if (config->engine != engine_id) {
+ if (config->ctx->current_config == config) config->ctx->configure = 1;
+ config->engine = engine_id;
+ }
+ return 0;
+}
+
+int rccConfigSetEngineByName(rcc_language_config *config, const char *name) {
+ rcc_engine_id engine_id;
+
+ engine_id = rccConfigGetEngineByName(config, name);
+ if (engine_id < 0) return -1;
+
+ return rccConfigSetEngine(config, engine_id);
+}
+
+int rccConfigSetCharset(rcc_language_config *config, rcc_class_id class_id, rcc_charset_id charset_id) {
+ unsigned int i;
+
+ if ((!config)||(!config->language)||(class_id < 0)||(class_id >= config->ctx->n_classes)||(charset_id<0)) return -1;
+
+ for (i=0;config->language->charsets[i];i++);
+ if (charset_id >= i) return -1;
+
+ if (config->charset[class_id] != charset_id) {
+ if (config->ctx->current_config == config) config->ctx->configure = 1;
+ config->charset[class_id] = charset_id;
+ }
+
+ return 0;
+}
+
+int rccConfigSetCharsetByName(rcc_language_config *config, rcc_class_id class_id, const char *name) {
+ rcc_charset_id charset_id;
+
+ charset_id = rccConfigGetCharsetByName(config, name);
+ if (charset_id < 0) return -1;
+
+ return rccConfigSetCharset(config, class_id, charset_id);
+}
+
+int rccConfigSetOption(rcc_language_config *config, rcc_option option, rcc_option_value value) {
+ if ((!config)||(option>=RCC_MAX_OPTIONS)) return -1;
+ if (config->options[option] != value) {
+ if (config->ctx->current_config == config) config->ctx->configure = 1;
+ config->options[option]=value;
+ }
+
+ return 0;
+}
+
+rcc_charset_id rccConfigGetLocaleCharset(rcc_language_config *config, const char *locale_variable) {
+ int err;
+ rcc_charset *charsets;
+ char stmp[RCC_MAX_CHARSET_CHARS+1];
+
+ if ((!config)||(!config->language)) return -1;
+
+ err = rccGetLocaleCharset(stmp, locale_variable?locale_variable:config->ctx->locale_variable, RCC_MAX_CHARSET_CHARS);
+ if (err) {
+ charsets=config->language->charsets;
+ if ((charsets[0])&&(charsets[1])) return 1;
+ return -1;
+ }
+
+ return rccConfigGetCharsetByName(config, stmp);
+}
diff --git a/src/plugin.c b/src/plugin.c
new file mode 100644
index 0000000..53ff00c
--- /dev/null
+++ b/src/plugin.c
@@ -0,0 +1,31 @@
+#ifdef RCC_PLUGINS
+# include <dlfcn.h>
+# ifndef RTLD_NOW
+# define RTLD_NOW 0
+# endif
+#endif /* RCC_PLUGINS */
+
+rcc_library_handle rccLibraryOpen(char *filename)
+{
+#ifdef RCC_PLUGINS
+ return (rcc_library_handle)dlopen(filename, RTLD_NOW);
+#else
+ return NULL;
+#endif /* RCC_PLUGINS */
+}
+
+void rccLibraryClose(rcc_library_handle handle)
+{
+#ifdef RCC_PLUGINS
+ dlclose(handle);
+#endif /* RCC_PLUGINS */
+}
+
+void* rccLibraryFind(rcc_library_handle handle, const char *symbol)
+{
+#ifdef RCC_PLUGINS
+ return dlsym(handle, symbol);
+#else
+ return NULL;
+#endif /* RCC_PLUGINS */
+}
diff --git a/src/plugin.h b/src/plugin.h
new file mode 100644
index 0000000..c6ed7b1
--- /dev/null
+++ b/src/plugin.h
@@ -0,0 +1,15 @@
+#ifndef _RCC_PLUGIN_H
+#define _RCC_PLUGIN_H
+#include "enca.h"
+
+#ifdef RCC_ENCA_DYNAMIC
+# define RCC_PLUGINS
+#endif /* RCC_ENCA_DYNAMIC */
+
+typedef void *rcc_library_handle;
+
+rcc_library_handle rccLibraryOpen(char *filename);
+void rccLibraryClose(rcc_library_handle handle);
+void* rccLibraryFind(rcc_library_handle handle, const char *symbol);
+
+#endif /* _RCC_PLUGIN_H */
diff --git a/src/recode.c b/src/recode.c
new file mode 100644
index 0000000..6d82daa
--- /dev/null
+++ b/src/recode.c
@@ -0,0 +1,228 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <locale.h>
+
+#include <librcd.h>
+#include "librcc.h"
+
+#include "fs.h"
+#include "config.h"
+
+
+static void rccIConvCopySymbol(char **in_buf, int *in_left, char **out_buf, int *out_left) {
+ if ((out_left>0)&&(in_left>0)) {
+ (**out_buf)=(**in_buf);
+ (*out_buf)++;
+ (*in_buf)++;
+ (*in_left)--;
+ (*out_left)--;
+ }
+}
+
+static int rccIConvUTFBytes(unsigned char c) {
+ int j;
+ if (c<128) return 1;
+
+ for (j=6;j>=0;j--)
+ if ((c&bit(j))==0) break;
+
+ if ((j==0)||(j==6)) return 1;
+ return 6-j;
+}
+
+static int rccIConv(rcc_context *ctx, iconv_t icnv, char *buf, int len) {
+ char *in_buf, *out_buf, *res, err;
+ int in_left, out_left, olen;
+ int ub, utf_mode=0;
+ int errors=0;
+
+ if ((!buf)||(!ctx)||(icnv == (iconv_t)-1)) return -1;
+
+ len = STRNLEN(buf,len);
+
+ if (iconv(icnv, NULL, NULL, NULL, NULL) == -1) return -1;
+
+loop_restart:
+ errors = 0;
+ in_buf = buf;
+ in_left = len;
+ out_buf = ctx->tmpbuffer;
+ out_left = RCC_MAX_STRING_CHARS;
+
+loop:
+ err=iconv(icnv, &in_buf, &in_left, &out_buf, &out_left);
+ if (err<0) {
+ if (errno==E2BIG) {
+ *(int*)(ctx->tmpbuffer+(CHARSET_MAX_STRING_SIZE-sizeof(int)))=0;
+ } else if (errno==EILSEQ) {
+ if (errors++<CHARSET_MAX_ERRORS) {
+ for (ub=utf_mode?rccIConvUTFBytes(*in_buf):1;ub>0;ub--)
+ rccIConvCopySymbol(&in_buf, &in_left, &out_buf, &out_left);
+ if (in_left>0) goto loop;
+ } else if (!utf_mode) {
+ utf_mode = 1;
+ goto loop_restart;
+ } else {
+ return -1;
+ }
+ } else {
+ return -1;
+ }
+ }
+
+ return CHARSET_MAX_STRING_SIZE - out_left;
+}
+
+
+static charset_id rccIConvAuto(rcc_context *ctx, rcc_class_id class_id, char *buf, int len) {
+ rcc_class_type class_type;
+
+ if ((!ctx)||(!buf)) return -1;
+
+ class_type = rccGetClassType(ctx, class_id);
+ if ((class_type == RCC_CLASS_STANDARD)||((class_type == RCC_CLASS_FS)&&(rccGetOption(ctx, RCC_AUTODETECT_FS_TITLES)))) {
+ engine = rccGetCurrentEngine(ctx);
+ if ((!engine)||(!engine->func)||(!stricmp(engine->title, "off"))||(!strcmp(engine->title, "dissable"))) return -1;
+
+ return engine->func(buf, len);
+ }
+
+ return -1;
+}
+
+rcc_string rccFrom(rcc_context *ctx, rcc_class_id class_id, const char *buf, int len, int *rlen) {
+ int err;
+ rcc_language_id language_id;
+ rcc_charset_id charset_id;
+ iconv_t icnv = (iconv_t)-1;
+ char *result;
+
+ if ((!ctx)||(class_id<0)||(class_id>=ctx->n_classes)||(!buf)) return NULL;
+
+ err = rccConfigure(ctx);
+ if (err) return NULL;
+
+
+ language_id = rccGetCurrentLanguage(ctx);
+ // DS: Learning. check database (language_id)
+
+ charset_id = rccIConvAuto(ctx, buf, len);
+ if (charset_id > 0) icnv = ctx->iconv_auto[charset_id];
+ if (icnv == (iconv_t)-1) {
+ icnv = ctx->iconv_from[class_id];
+ if (icnv == (iconv_t)-1) return NULL;
+ }
+
+ if (icnv == (iconv_t)-2) {
+ result = rccCreateString(language_id, buf, len, rlen);
+ } else {
+ err = rccIConv(ctx, icnv, buf, len);
+ if (err<=0) return NULL;
+ result = rccCreateString(language_id, ctx->tmpbuffer, err, rlen);
+ }
+
+ // DS: Learning. write database
+
+ return result;
+}
+
+char *rccTo(rcc_context *ctx, rcc_class_id class_id, const rcc_string buf, int len, int *rlen) {
+ int err;
+ char *result;
+ char *prefix, *name;
+ rcc_language_id language_id;
+ rcc_charset_id charset_id;
+ iconv_t icnv;
+
+ if ((!ctx)||(class_id<0)||(class_id>=ctx->n_classes)||(!buf)) return NULL;
+
+ language_id = rccCheckString(ctx, buf);
+ if (!language_id) return NULL;
+
+ err = rccConfigure(ctx);
+ if (err) return NULL;
+
+ icnv = ctx->iconv_to[class_id];
+
+ if ((class_type == RCC_CLASS_FS)&&(rccGetOption(ctx, RCC_AUTODETECT_FS_NAMES))) {
+ // DS: file_names (autodetect fspath)
+ prefix = NULL; name = buf + sizeof(rcc_string_header);
+ err = rccFS0(NULL, buf, &prefix, &name);
+ if (!err) {
+ result = rccFS3(ctx, language_id, class_id, prefix, name, 0, rlen);
+ return result;
+ }
+ }
+
+ if (icnv == (iconv_t)-1) return NULL;
+ if (icnv == (iconv_t)-2) {
+ result = rccParseString(ctx, buf, len, rlen);
+ } else {
+ err = rccIConv(ctx, icnv, buf + sizeof(rcc_string_header), len?len-sizeof(rcc_string_header):0);
+ if (err<=0) return NULL;
+
+ result = rccCreateAnswer(ctx, err, rlen);
+ }
+
+ return result;
+}
+
+char *rccRecode(rcc_context *ctx, rcc_class_id from, rcc_class_id to, const char *buf, int len, int *rlen) {
+ int nlen;
+ rcc_string stmp;
+ charset_id from_charset_id, to_charset_id;
+
+ if ((!ctx)||(from<0)||(from>=ctx->n_classes)||(to<0)||(to>=ctx->n_classes)||(!buf)) return NULL;
+
+ if ((class_type == RCC_CLASS_FS)&&(rccGetOption(ctx, RCC_AUTODETECT_FS_NAMES))) goto recoding;
+
+ from_charset_id = rccIConvAuto(ctx, buf, len);
+ if (from_charset_id>0) {
+ from_charset = rccGetAutoCharsetName(ctx, from_charset_id);
+ to_charset = rccGetCurrentCharsetName(ctx, to);
+ if ((from_charset)&&(to_charset)&&(!stricmp(from_charset, to_charset))) return NULL;
+ } else {
+ from_charset_id = rccGetCurrentCharset(ctx, from)
+ to_charset_id = rccGetCurrentCharset(ctx, to);
+ if (from_charset_id == to_charset_id) return NULL;
+ }
+
+recoding:
+ stmp = rccFrom(ctx, from, buf, len, &nlen);
+ if (stmp) {
+ buf = rccTo(ctx, to, stmp, nlen, rlen);
+ free(stmp);
+ return buf;
+ }
+
+ return rccTo(ctx, to, buf, len, rlen);
+}
+
+char *rccFS(rcc_context *ctx, rcc_class_id from, rcc_class_id to, const char *fspath, const char *path, const char *filename) {
+ int err;
+ char *prefix = path, *name = filename;
+ rcc_string string;
+
+ char *stmp;
+ char *result_fn = NULL;
+
+
+ err = rccFS1(ctx, fspath, &prefix, &name);
+ if (err) {
+ if (err<0) return NULL;
+ return name;
+ }
+
+ string = rccFrom(ctx, from, name, len, rlen);
+ if (string) {
+ language_id = rccGetCurrentLanguage(ctx);
+ result = rccFS3(ctx, language_id, to, prefix, string + sizeof(rcc_string_header), 0, NULL);
+ free(string);
+ } else result = NULL;
+
+ free(prefix);
+ free(name);
+
+ return result;
+}
diff --git a/src/string.c b/src/string.c
new file mode 100644
index 0000000..85a5767
--- /dev/null
+++ b/src/string.c
@@ -0,0 +1,74 @@
+#include <stdio.h>
+#include <string.h>
+
+rcc_string rccStringInit(rcc_language_id language_id, const char *buf, int len, int *rlen) {
+ rcc_string_header header = {RCC_STRING_MAGIC, language_id};
+
+ len = STRNLEN(buf, len);
+
+ res = (char*)malloc(len+sizeof(rcc_string_header)+1);
+ if (!res) return NULL;
+
+ strncpy(res + sizeof(rcc_string_header), buf, len);
+ res[sizeof(rcc_string_header) + 1 + len] = 0;
+
+ memcpy(res, &header, sizeof(rcc_string_header));
+
+ if (rlen) *rlen = len + sizeof(rcc_string_header);
+ return (rcc_string)res;
+}
+
+void rccStringFree(rcc_string str) {
+ if (str) free(str);
+}
+
+rcc_language_id rccStringCheck(const rcc_string str) {
+ int len;
+ rcc_string_header *header;
+
+ len = strlen(str);
+
+ if ((!str)||(len<=sizeof(unsigned int))||(*((unsigned int*)(str))!=RCC_STRING_MAGIC)) return 0;
+
+ header = (rcc_string_header*)(str);
+ return header->language_id;
+}
+
+const char *rccStringGet(const rcc_string str) {
+ if (rccStringCheck(str)) return str + sizeof(rcc_string_header);
+ return (const char *)str;
+}
+
+char *rccStringExtract(const rcc_string buf, int len, int *rlen) {
+ char *res;
+
+ len = STRNLEN(buf, len) - sizeof(rcc_string_header);
+ if (len<0) return NULL;
+
+ res = (char*)malloc(len+1);
+ if (!res) return NULL;
+
+ strncpy(res, buf + sizeof(rcc_string_header), len);
+ res[len] = 0;
+
+ if (rlen) *rlen = len;
+
+ return res;
+}
+
+char *rccStringCmp(const rcc_string str1, const rcc_string str2) {
+ return strcmp(rccStringGet(str1), rccStringGet(str2));
+}
+
+char *rccStringNCmp(const rcc_string str1, const rcc_string str2, size_t n) {
+ return strncmp(rccStringGet(str1), rccStringGet(str2), n);
+}
+
+char *rccStringCaseCmp(const rcc_string str1, const rcc_string str2) {
+ return strcasecmp(rccStringGet(str1), rccStringGet(str2));
+}
+
+char *rccStringNCaseCmp(const rcc_string str1, const rcc_string str2, size_t n) {
+ return strncasecmp(rccStringGet(str1), rccStringGet(str2), n);
+}
+
diff --git a/src/xml.c b/src/xml.c
new file mode 100644
index 0000000..a2225f2
--- /dev/null
+++ b/src/xml.c
@@ -0,0 +1,8 @@
+
+int rccSave(rcc_context *ctx) {
+ return 0;
+}
+
+int rccLoad(rcc_context *ctx) {
+ return 0;
+}