49static uint64_t msgcat_plural_eval(
const char *, uint64_t );
50static const char* msgcat_mo_lookup(
const void *p,
size_t size,
const char *s );
62 p->map_size = map_size;
64 const char *rule =
"n!=1;";
66 const char *r = msgcat_mo_lookup(p->map, p->map_size,
"");
68 while (r && strncmp(r,
"Plural-Forms:", 13)) {
74 while (isspace(*r)) r++;
75 if (!strncmp(r,
"nplurals=", 9)) {
76 np = strtoul(r+9, &z, 10);
79 while (*r && *r !=
';') r++;
82 while (isspace(*r)) r++;
83 if (!strncmp(r,
"plural=", 7))
88 p->plural_rule = rule;
103 const char *trans = msgcat_mo_lookup(p->map, p->map_size, msgid1);
104 if (!trans)
return NULL;
109 if (msgid2 && p->nplurals) {
110 uint64_t plural = msgcat_plural_eval(p->plural_rule, n);
111 if (plural > p->nplurals)
return NULL;
113 size_t rem = p->map_size - (trans - (
char *)p->map);
114 size_t l = strnlen(trans, rem);
125static inline uint32_t swapc(uint32_t x,
int c)
127 return c ? (x>>24) | (x>>8&0xff00) | (x<<8&0xff0000) | (x<<24) : x;
130const char *msgcat_mo_lookup(
const void *p,
size_t size,
const char *s)
132 const uint32_t *mo = p;
133 int sw = *mo - 0x950412de;
134 uint32_t b = 0, n = swapc(mo[2], sw);
135 uint32_t o = swapc(mo[3], sw);
136 uint32_t t = swapc(mo[4], sw);
137 if (n>=size/4 || o>=size-4*n || t>=size-4*n || ((o|t)%4))
142 uint32_t ol = swapc(mo[o+2*(b+n/2)], sw);
143 uint32_t os = swapc(mo[o+2*(b+n/2)+1], sw);
144 if (os >= size || ol >= size-os || ((
char *)p)[os+ol])
146 int sign = strcmp(s, (
char *)p + os);
148 uint32_t tl = swapc(mo[t+2*(b+n/2)], sw);
149 uint32_t ts = swapc(mo[t+2*(b+n/2)+1], sw);
150 if (ts >= size || tl >= size-ts || ((
char *)p)[ts+tl])
152 return (
char *)p + ts;
154 else if (n == 1)
return 0;
171 const uint32_t *mo = (uint32_t*) buf;
172 int sw = *mo - 0x950412de;
173 return swapc(mo[2], sw);
205static const char *skipspace(
const char *s)
207 while (isspace(*s)) s++;
211static const char *evalexpr(
struct st *
st,
const char *s,
int d);
213static const char *evalprim(
struct st *
st,
const char *s,
int d)
216 if (--
d < 0)
return "";
219 st->r = strtoul(s, &e, 10);
220 if (e == s ||
st->r == UINT64_MAX)
return "";
225 return skipspace(s+1);
228 s = evalexpr(
st, s+1,
d);
229 if (*s !=
')')
return "";
230 return skipspace(s+1);
233 s = evalprim(
st, s+1,
d);
240static int binop(
struct st *
st,
int op, uint64_t left)
242 uint64_t a = left, b =
st->r;
244 case 0:
st->r = a||b;
return 0;
245 case 1:
st->r = a&&b;
return 0;
246 case 2:
st->r = a==b;
return 0;
247 case 3:
st->r = a!=b;
return 0;
248 case 4:
st->r = a>=b;
return 0;
249 case 5:
st->r = a<=b;
return 0;
250 case 6:
st->r = a>b;
return 0;
251 case 7:
st->r = a<b;
return 0;
252 case 8:
st->r = a+b;
return 0;
253 case 9:
st->r = a-b;
return 0;
254 case 10:
st->r = a*b;
return 0;
255 case 11:
if (b) {
st->r = a%b;
return 0;}
return 1;
256 case 12:
if (b) {
st->r = a/b;
return 0;}
return 1;
261static const char *parseop(
struct st *
st,
const char *s)
263 static const char opch[11] =
"|&=!><+-*%/";
264 static const char opch2[6] =
"|&====";
269 if (i<6 && s[1] == opch2[i]) {
283static const char *evalbinop(
struct st *
st,
const char *s,
int minprec,
int d)
285 static const char prec[14] = {1,2,3,3,4,4,4,4,5,5,6,6,6,0};
289 s = evalprim(
st, s,
d);
298 if (prec[op] <= minprec)
301 s = evalbinop(
st, s, prec[op],
d);
302 if (binop(
st, op, left))
307static const char *evalexpr(
struct st *
st,
const char *s,
int d)
312 s = evalbinop(
st, s, 0,
d);
316 s = evalexpr(
st, s+1,
d);
320 s = evalexpr(
st, s+1,
d);
321 st->r = a ? b :
st->r;
325uint64_t msgcat_plural_eval(
const char *s, uint64_t n)
329 s = evalexpr(&
st, s, 100);
330 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.