implement mo file string lookup for translations
authorRich Felker <dalias@aerifal.cx>
Sat, 26 Jul 2014 06:34:09 +0000 (02:34 -0400)
committerRich Felker <dalias@aerifal.cx>
Sat, 26 Jul 2014 06:34:09 +0000 (02:34 -0400)
the core is based on a binary search; hash table is not used. both
native and reverse-endian mo files are supported. all offsets read
from the mapped mo file are checked against the mapping size to
prevent the possibility of reads outside the mapping.

this commit has no observable effects since there are not yet any
callers to the message translation code.

src/internal/locale_impl.h
src/locale/__lctrans.c [new file with mode: 0644]
src/locale/__mo_lookup.c [new file with mode: 0644]
src/locale/__setlocalecat.c

index 0ee72d3e657f966c9c0a22217ac494872169738b..9142f0c278133b44e91c19ee1a1852cc056db52b 100644 (file)
@@ -13,6 +13,12 @@ struct __locale_map {
 };
 
 int __setlocalecat(locale_t, int, const char *);
+const char *__mo_lookup(const void *, size_t, const char *);
+const char *__lctrans(const char *, const struct __locale_map *);
+const char *__lctrans_cur(const char *);
+
+#define LCTRANS(msg, lc, loc) __lctrans(msg, (loc)->cat[(lc)-2])
+#define LCTRANS_CUR(msg) __lctrans_cur(msg)
 
 #define CURRENT_LOCALE \
        (libc.uselocale_cnt ? __pthread_self()->locale : &libc.global_locale)
diff --git a/src/locale/__lctrans.c b/src/locale/__lctrans.c
new file mode 100644 (file)
index 0000000..2769c08
--- /dev/null
@@ -0,0 +1,20 @@
+#include <locale.h>
+#include "locale_impl.h"
+#include "libc.h"
+
+const char *dummy(const char *msg, const struct __locale_map *lm)
+{
+       return msg;
+}
+
+weak_alias(dummy, __lctrans_impl);
+
+const char *__lctrans(const char *msg, const struct __locale_map *lm)
+{
+       return __lctrans_impl(msg, lm);
+}
+
+const char *__lctrans_cur(const char *msg)
+{
+       return __lctrans_impl(msg, CURRENT_LOCALE->cat[LC_MESSAGES-2]);
+}
diff --git a/src/locale/__mo_lookup.c b/src/locale/__mo_lookup.c
new file mode 100644 (file)
index 0000000..8112d91
--- /dev/null
@@ -0,0 +1,38 @@
+#include <stdint.h>
+#include <string.h>
+
+static inline uint32_t swapc(uint32_t x, int c)
+{
+       return c ? x>>24 | x>>8&0xff00 | x<<8&0xff0000 | x<<24 : x;
+}
+
+const char *__mo_lookup(const void *p, size_t size, const char *s)
+{
+       const uint32_t *mo = p;
+       int sw = *mo - 0x950412de;
+       uint32_t b = 0, n = swapc(mo[2], sw);
+       uint32_t o = swapc(mo[3], sw);
+       uint32_t t = swapc(mo[4], sw);
+       if (n>=size/4 || o>=size-4*n || t>=size-4*n || ((o|t)%4))
+               return 0;
+       o/=4;
+       t/=4;
+       for (;;) {
+               uint32_t os = swapc(mo[o+2*(b+n/2)+1], sw);
+               if (os >= size) return 0;
+               int sign = strcmp(s, (char *)p + os);
+               if (!sign) {
+                       uint32_t ts = swapc(mo[t+2*(b+n/2)+1], sw);
+                       if (ts >= size) return 0;
+                       return (char *)p + ts;
+               }
+               else if (n == 1) return 0;
+               else if (sign < 0)
+                       n /= 2;
+               else {
+                       b += n/2;
+                       n -= n/2;
+               }
+       }
+       return 0;
+}
index bbecde413f6b772074ca2d6e4be513f3ad1c9189..44385e02c6584e10a393b5ee916db513023529cc 100644 (file)
@@ -4,6 +4,13 @@
 #include "libc.h"
 #include "atomic.h"
 
+const char *__lctrans_impl(const char *msg, const struct __locale_map *lm)
+{
+       const char *trans = 0;
+       if (lm) trans = __mo_lookup(lm->map, lm->map_size, msg);
+       return trans ? trans : msg;
+}
+
 const unsigned char *__map_file(const char *, size_t *);
 int __munmap(void *, size_t);
 char *__strchrnul(const char *, int);