46static uint64_t msgcat_plural_eval(
const char *, uint64_t );
47static const char* msgcat_mo_lookup(
const void *p,
size_t size,
const char *s );
59 p->map_size = map_size;
61 const char *rule =
"n!=1;";
63 const char *r = msgcat_mo_lookup(p->map, p->map_size,
"");
65 while (r && strncmp(r,
"Plural-Forms:", 13)) {
71 while (isspace(*r)) r++;
72 if (!strncmp(r,
"nplurals=", 9)) {
73 np = strtoul(r+9, &z, 10);
76 while (*r && *r !=
';') r++;
79 while (isspace(*r)) r++;
80 if (!strncmp(r,
"plural=", 7))
85 p->plural_rule = rule;
100 const char *trans = msgcat_mo_lookup(p->map, p->map_size, msgid1);
101 if (!trans)
return NULL;
106 if (msgid2 && p->nplurals) {
107 uint64_t plural = msgcat_plural_eval(p->plural_rule, n);
108 if (plural > p->nplurals)
return NULL;
110 size_t rem = p->map_size - (trans - (
char *)p->map);
111 size_t l = strnlen(trans, rem);
122static inline uint32_t swapc(uint32_t x,
int c)
124 return c ? (x>>24) | (x>>8&0xff00) | (x<<8&0xff0000) | (x<<24) : x;
127const char *msgcat_mo_lookup(
const void *p,
size_t size,
const char *s)
129 const uint32_t *mo = p;
130 int sw = *mo - 0x950412de;
131 uint32_t b = 0, n = swapc(mo[2], sw);
132 uint32_t o = swapc(mo[3], sw);
133 uint32_t t = swapc(mo[4], sw);
134 if (n>=size/4 || o>=size-4*n || t>=size-4*n || ((o|t)%4))
139 uint32_t ol = swapc(mo[o+2*(b+n/2)], sw);
140 uint32_t os = swapc(mo[o+2*(b+n/2)+1], sw);
141 if (os >= size || ol >= size-os || ((
char *)p)[os+ol])
143 int sign = strcmp(s, (
char *)p + os);
145 uint32_t tl = swapc(mo[t+2*(b+n/2)], sw);
146 uint32_t ts = swapc(mo[t+2*(b+n/2)+1], sw);
147 if (ts >= size || tl >= size-ts || ((
char *)p)[ts+tl])
149 return (
char *)p + ts;
151 else if (n == 1)
return 0;
168 const uint32_t *mo = (uint32_t*) buf;
169 int sw = *mo - 0x950412de;
170 return swapc(mo[2], sw);
202static const char *skipspace(
const char *s)
204 while (isspace(*s)) s++;
208static const char *evalexpr(
struct st *
st,
const char *s,
int d);
210static const char *evalprim(
struct st *
st,
const char *s,
int d)
213 if (--
d < 0)
return "";
216 st->r = strtoul(s, &e, 10);
217 if (e == s ||
st->r == UINT64_MAX)
return "";
222 return skipspace(s+1);
225 s = evalexpr(
st, s+1,
d);
226 if (*s !=
')')
return "";
227 return skipspace(s+1);
230 s = evalprim(
st, s+1,
d);
237static int binop(
struct st *
st,
int op, uint64_t left)
239 uint64_t a = left, b =
st->r;
241 case 0:
st->r = a||b;
return 0;
242 case 1:
st->r = a&&b;
return 0;
243 case 2:
st->r = a==b;
return 0;
244 case 3:
st->r = a!=b;
return 0;
245 case 4:
st->r = a>=b;
return 0;
246 case 5:
st->r = a<=b;
return 0;
247 case 6:
st->r = a>b;
return 0;
248 case 7:
st->r = a<b;
return 0;
249 case 8:
st->r = a+b;
return 0;
250 case 9:
st->r = a-b;
return 0;
251 case 10:
st->r = a*b;
return 0;
252 case 11:
if (b) {
st->r = a%b;
return 0;}
return 1;
253 case 12:
if (b) {
st->r = a/b;
return 0;}
return 1;
258static const char *parseop(
struct st *
st,
const char *s)
260 static const char opch[11] =
"|&=!><+-*%/";
261 static const char opch2[6] =
"|&====";
266 if (i<6 && s[1] == opch2[i]) {
280static const char *evalbinop(
struct st *
st,
const char *s,
int minprec,
int d)
282 static const char prec[14] = {1,2,3,3,4,4,4,4,5,5,6,6,6,0};
286 s = evalprim(
st, s,
d);
295 if (prec[op] <= minprec)
298 s = evalbinop(
st, s, prec[op],
d);
299 if (binop(
st, op, left))
304static const char *evalexpr(
struct st *
st,
const char *s,
int d)
309 s = evalbinop(
st, s, 0,
d);
313 s = evalexpr(
st, s+1,
d);
317 s = evalexpr(
st, s+1,
d);
318 st->r = a ? b :
st->r;
322uint64_t msgcat_plural_eval(
const char *s, uint64_t n)
326 s = evalexpr(&
st, s, 100);
327 return *s ==
';' ?
st.r : UINT64_MAX;
const char * msgcat_ngettext(const msgcat_t *p, const char *msgid1, const char *msgid2, uint64_t n)
Return a translation, if present, from the given message catalog.
void msgcat_init(msgcat_t *p, const void *map, size_t map_size)
Initialize a msgcat_t, given the contents and content-length of a .mo file.
uint32_t msgcat_nstringsFromHeader(const char buf[12])
Return the number of strings in a message catalog, given its first 12 bytes.