summaryrefslogtreecommitdiffstats
path: root/i18npool
diff options
context:
space:
mode:
authorEike Rathke <erack@redhat.com>2012-08-09 16:06:41 +0200
committerEike Rathke <erack@redhat.com>2012-08-09 16:11:19 +0200
commit1150a1a8eb1759160b9d88e99d95e5ad082f40be (patch)
tree2f79b92fc2f2dd895020dab64bf30dc4ff8a4f2b /i18npool
parentBin ScXMLImport::GetVisibleSheet() (diff)
downloadcore-1150a1a8eb1759160b9d88e99d95e5ad082f40be.tar.gz
core-1150a1a8eb1759160b9d88e99d95e5ad082f40be.zip
implemented simple liblangtag replacement for iOS and Android
Diffstat (limited to 'i18npool')
-rw-r--r--i18npool/source/languagetag/languagetag.cxx129
-rw-r--r--i18npool/source/languagetag/simple-langtag.cxx401
2 files changed, 408 insertions, 122 deletions
diff --git a/i18npool/source/languagetag/languagetag.cxx b/i18npool/source/languagetag/languagetag.cxx
index 728e70a43e43..d7c6b0f79f68 100644
--- a/i18npool/source/languagetag/languagetag.cxx
+++ b/i18npool/source/languagetag/languagetag.cxx
@@ -15,128 +15,13 @@
#if !defined(ANDROID) && !defined(IOS)
#include <liblangtag/langtag.h>
-
-#elif defined(ANDROID) || defined(IOS)
-
-// Completely dummy implementation, once this actually starts getting used at
-// run-time will need to do something.
-
-// For iOS probably can use NSLocale, that should have more or less required
-// functionality. If it is good enough, it could be used for Mac OS X,
-// too. For Android, maybe java.util.Locale, although it definitely lacks in
-// functionality.
-
-typedef char gchar;
-typedef struct {
- char *message;
-} GError;
-
-static void g_free(void *p)
-{
- free(p);
-}
-
-static void g_error_free(GError *error)
-{
- (void) error;
-}
-
-typedef void lt_tag_t;
-typedef void lt_lang_t;
-typedef void lt_script_t;
-typedef void lt_region_t;
-
-static void lt_db_initialize(void)
-{
-}
-
-static void lt_db_finalize(void)
-{
-}
-
-static void lt_db_set_datadir(const char *dir)
-{
- (void) dir;
-}
-
-static lt_tag_t *lt_tag_new(void)
-{
- return NULL;
-}
-
-static lt_tag_t *lt_tag_copy(lt_tag_t *tag)
-{
- (void) tag;
- return NULL;
-}
-
-static void lt_tag_unref(lt_tag_t *tag)
-{
- (void) tag;
-}
-
-static int lt_tag_parse(lt_tag_t *tag,
- const char *tag_string,
- GError **error)
-{
- (void) tag;
- (void) tag_string;
- (void) error;
-
- return -1;
-}
-
-static char *lt_tag_canonicalize(lt_tag_t *tag,
- GError **error)
-{
- (void) tag;
- (void) error;
-
- return NULL;
-}
-
-static const lt_lang_t *lt_tag_get_language(const lt_tag_t *tag)
-{
- (void) tag;
-
- return NULL;
-}
-
-static const lt_script_t *lt_tag_get_script(const lt_tag_t *tag)
-{
- (void) tag;
-
- return NULL;
-}
-
-static const lt_region_t *lt_tag_get_region(const lt_tag_t *tag)
-{
- (void) tag;
-
- return NULL;
-}
-
-static const gchar *lt_lang_get_tag(const lt_lang_t *lang)
-{
- (void) lang;
-
- return NULL;
-}
-
-static const gchar *lt_script_get_tag(const lt_script_t *script)
-{
- (void) script;
-
- return NULL;
-}
-
-static const gchar *lt_region_get_tag(const lt_region_t *region)
-{
- (void) region;
-
- return NULL;
-}
-
+#else
+/* Replacement code for LGPL phobic and Android systems.
+ * For iOS we could probably use NSLocale instead, that should have more or
+ * less required functionality. If it is good enough, it could be used for Mac
+ * OS X, too.
+ */
+#include "simple-langtag.cxx"
#endif
//#define erDEBUG
diff --git a/i18npool/source/languagetag/simple-langtag.cxx b/i18npool/source/languagetag/simple-langtag.cxx
new file mode 100644
index 000000000000..71317493612d
--- /dev/null
+++ b/i18npool/source/languagetag/simple-langtag.cxx
@@ -0,0 +1,401 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+/** Cheap and cheesy replacement code for liblangtag on systems that do not
+ allow / want LGPL code or dependencies on glib.
+
+ XXX NOTE: This code does not check language tags for validity or if they
+ are registered with IANA, does not canonicalize or strip default script
+ tags if included nor does it do any other fancy stuff that liblangtag is
+ capable of. It just makes depending code work without.
+ */
+
+#include <cstdlib>
+#include <cstring>
+#include <cstdio>
+
+namespace {
+
+typedef char gchar;
+typedef void* gpointer;
+typedef int gint;
+typedef gint gboolean;
+
+struct GError {
+ char *message;
+ GError() : message(NULL) {}
+};
+
+static gpointer g_malloc(size_t s)
+{
+ return malloc(s);
+}
+
+static void g_free(gpointer p)
+{
+ if (p)
+ free(p);
+}
+
+static void g_error_free(GError *error)
+{
+ if (error)
+ {
+ g_free( error->message);
+ g_free( error);
+ }
+}
+
+struct my_ref
+{
+ sal_uInt32 mnRef;
+ explicit my_ref() : mnRef(1) {}
+ virtual ~my_ref() {}
+ void incRef() { ++mnRef; }
+ void decRef() { if (--mnRef == 0) delete this; }
+};
+
+struct my_t_impl : public my_ref
+{
+ gchar* mpStr;
+ explicit my_t_impl() : my_ref(), mpStr(NULL) {}
+ virtual ~my_t_impl() { g_free( mpStr); }
+ explicit my_t_impl( const my_t_impl& r )
+ :
+ my_ref(),
+ mpStr(r.mpStr ? strdup( r.mpStr) : NULL)
+ {
+ }
+ my_t_impl& operator=( const my_t_impl& r )
+ {
+ if (this == &r)
+ return *this;
+ g_free( mpStr);
+ mpStr = (r.mpStr ? strdup( r.mpStr) : NULL);
+ return *this;
+ }
+ void assign( const gchar* str )
+ {
+ g_free( mpStr);
+ mpStr = (str ? strdup( str) : NULL);
+ }
+ void assign( const gchar* str, const gchar* stop )
+ {
+ g_free( mpStr);
+ if (str && str < stop)
+ {
+ mpStr = static_cast<gchar*>(g_malloc( stop - str + 1));
+ memcpy( mpStr, str, stop - str);
+ mpStr[stop - str] = 0;
+ }
+ else
+ mpStr = NULL;
+ }
+ void append( const gchar* str, const gchar* stop )
+ {
+ if (str && str < stop)
+ {
+ size_t nOld = mpStr ? strlen( mpStr) : 0;
+ size_t nNew = nOld + (stop - str) + 1;
+ char* p = static_cast<gchar*>(g_malloc( nNew));
+ if (nOld)
+ memcpy( p, mpStr, nOld);
+ memcpy( p + nOld, str, stop - str);
+ p[nNew-1] = 0;
+ g_free( mpStr);
+ mpStr = p;
+ }
+ }
+ void zero()
+ {
+ g_free( mpStr);
+ mpStr = NULL;
+ }
+};
+
+struct lt_lang_t : public my_t_impl
+{
+ explicit lt_lang_t() : my_t_impl() {}
+ virtual ~lt_lang_t() {}
+};
+
+struct lt_script_t : public my_t_impl
+{
+ explicit lt_script_t() : my_t_impl() {}
+ virtual ~lt_script_t() {}
+};
+
+struct lt_region_t : public my_t_impl
+{
+ explicit lt_region_t() : my_t_impl() {}
+ virtual ~lt_region_t() {}
+};
+
+struct lt_tag_t : public my_t_impl
+{
+ lt_lang_t maLanguage;
+ lt_script_t maScript;
+ lt_region_t maRegion;
+ explicit lt_tag_t() : my_t_impl(), maLanguage(), maScript(), maRegion() {}
+ virtual ~lt_tag_t() {}
+ explicit lt_tag_t( const lt_tag_t& r )
+ :
+ my_t_impl( r),
+ maLanguage( r.maLanguage),
+ maScript( r.maScript),
+ maRegion( r.maRegion)
+ {
+ }
+ lt_tag_t& operator=( const lt_tag_t& r )
+ {
+ if (this == &r)
+ return *this;
+ my_t_impl::operator=( r);
+ maLanguage = r.maLanguage;
+ maScript = r.maScript;
+ maRegion = r.maRegion;
+ return *this;
+ }
+ void assign( const gchar* str )
+ {
+ maLanguage.zero();
+ maScript.zero();
+ maRegion.zero();
+ my_t_impl::assign( str);
+ }
+};
+
+static void lt_db_initialize() { }
+static void lt_db_finalize() { }
+static void lt_db_set_datadir( const char* /* dir */ ) { }
+
+static lt_tag_t* lt_tag_new(void)
+{
+ return new lt_tag_t;
+}
+
+static lt_tag_t* lt_tag_copy(lt_tag_t *tag)
+{
+ return (tag ? new lt_tag_t( *tag) : NULL);
+}
+
+static void lt_tag_unref(lt_tag_t *tag)
+{
+ if (tag)
+ tag->decRef();
+}
+
+/** See http://tools.ietf.org/html/rfc5646
+
+ We are simply ignorant of grandfathered (irregular and regular) subtags and
+ may either bail out or accept them, sorry (or not). However, we do accept
+ any i-* irregular and x-* privateuse. Subtags are not checked for validity
+ (alpha, digit, registered, ...).
+ */
+static gboolean lt_tag_parse(lt_tag_t *tag,
+ const gchar *tag_string,
+ GError **error)
+{
+ (void) error;
+ if (!tag)
+ return 0;
+ tag->assign( tag_string);
+ if (!tag_string)
+ return 0;
+ // In case we supported other subtags this would get more complicated.
+ my_t_impl* aSubtags[] = { &tag->maLanguage, &tag->maScript, &tag->maRegion, NULL };
+ my_t_impl** ppSub = &aSubtags[0];
+ const gchar* pStart = tag_string;
+ const gchar* p = pStart;
+ const gchar* pEnd = pStart + strlen( pStart); // scanning includes \0
+ bool bStartLang = true;
+ bool bPrivate = false;
+ for ( ; p <= pEnd && ppSub && *ppSub; ++p)
+ {
+ if (p == pEnd || *p == '-')
+ {
+ size_t nLen = p - pStart;
+ if (*ppSub == &tag->maLanguage)
+ {
+ if (bStartLang)
+ {
+ bStartLang = false;
+ switch (nLen)
+ {
+ case 1: // irregular or privateuse
+ if (*pStart == 'i' || *pStart == 'x')
+ {
+ (*ppSub)->assign( pStart, p);
+ bPrivate = true;
+ }
+ else
+ return 0; // bad
+ break;
+ case 2: // ISO 639 alpha-2
+ case 3: // ISO 639 alpha-3
+ (*ppSub)->assign( pStart, p);
+ break;
+ case 4: // reserved for future use
+ return 0; // bad
+ break;
+ case 5:
+ case 6:
+ case 7:
+ case 8: // registered language subtag
+ (*ppSub++)->assign( pStart, p);
+ break;
+ default:
+ return 0; // bad
+ }
+ }
+ else
+ {
+ if (nLen > 8)
+ return 0; // bad
+ if (bPrivate)
+ {
+ // Any combination of "x" 1*("-" (2*8alphanum))
+ // allowed, store first as language and return ok.
+ // For i-* simply assume the same.
+ (*ppSub)->append( pStart-1, p);
+ return !0; // ok
+ }
+ else if (nLen == 3)
+ {
+ // extlang subtag, 1 to 3 allowed we don't check that.
+ // But if it's numeric it's a region UN M.49 code
+ // instead and no script subtag is present, so advance.
+ if ('0' <= *pStart && *pStart <= '9')
+ {
+ ppSub += 2; // &tag->maRegion XXX watch this when inserting fields
+ --p;
+ continue; // for
+ }
+ else
+ (*ppSub)->append( pStart-1, p);
+ }
+ else
+ {
+ // Not part of language subtag, advance.
+ ++ppSub;
+ --p;
+ continue; // for
+ }
+ }
+ }
+ else if (*ppSub == &tag->maScript)
+ {
+ switch (nLen)
+ {
+ case 4:
+ // script subtag, or a (DIGIT 3alphanum) variant with
+ // no script and no region in which case we stop
+ // parsing.
+ if ('0' <= *pStart && *pStart <= '9')
+ ppSub = NULL;
+ else
+ (*ppSub++)->assign( pStart, p);
+ break;
+ case 3:
+ // This may be a region UN M.49 code if 3DIGIT and no
+ // script code present. Just check first character and
+ // advance.
+ if ('0' <= *pStart && *pStart <= '9')
+ {
+ ++ppSub;
+ --p;
+ continue; // for
+ }
+ else
+ return 0; // bad
+ break;
+ case 2:
+ // script omitted, region subtag, advance.
+ ++ppSub;
+ --p;
+ continue; // for
+ break;
+ case 1:
+ // script omitted, region omitted, extension subtag
+ // with singleton, stop parsing
+ ppSub = NULL;
+ break;
+ case 5:
+ case 6:
+ case 7:
+ case 8:
+ // script omitted, region omitted, variant subtag, stop
+ // parsing.
+ ppSub = NULL;
+ default:
+ return 0; // bad
+ }
+ }
+ else if (*ppSub == &tag->maRegion)
+ {
+ if (nLen == 2 || nLen == 3)
+ (*ppSub++)->assign( pStart, p);
+ else
+ return 0; // bad
+ }
+ pStart = p+1;
+ }
+ }
+ return !0;
+}
+
+static gchar* lt_tag_canonicalize(lt_tag_t *tag,
+ GError **error)
+{
+ (void) error;
+ return tag && tag->mpStr ? strdup( tag->mpStr) : NULL;
+}
+
+static const lt_lang_t* lt_tag_get_language(const lt_tag_t *tag)
+{
+ return tag && tag->maLanguage.mpStr ? &tag->maLanguage : NULL;
+}
+
+static const lt_script_t *lt_tag_get_script(const lt_tag_t *tag)
+{
+ return tag && tag->maScript.mpStr ? &tag->maScript : NULL;
+}
+
+static const lt_region_t *lt_tag_get_region(const lt_tag_t *tag)
+{
+ return tag && tag->maRegion.mpStr ? &tag->maRegion : NULL;
+}
+
+static const gchar *lt_lang_get_tag(const lt_lang_t *lang)
+{
+ return lang ? lang->mpStr : NULL;
+}
+
+static const gchar *lt_script_get_tag(const lt_script_t *script)
+{
+ return script ? script->mpStr : NULL;
+}
+
+static const gchar *lt_region_get_tag(const lt_region_t *region)
+{
+ return region ? region->mpStr : NULL;
+}
+
+static void lt_tag_dump(const lt_tag_t *tag)
+{
+ fprintf( stderr, "\n");
+ fprintf( stderr, "SimpleLangtag langtag: %s\n", tag->mpStr);
+ fprintf( stderr, "SimpleLangtag language: %s\n", tag->maLanguage.mpStr);
+ fprintf( stderr, "SimpleLangtag script: %s\n", tag->maScript.mpStr);
+ fprintf( stderr, "SimpleLangtag region: %s\n", tag->maRegion.mpStr);
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */