From 438a47cf6da6dba04b04fee983c247cc13430b6c Mon Sep 17 00:00:00 2001 From: rofl0r Date: Wed, 13 Aug 2014 17:36:28 +0200 Subject: implement sysdep replacement as proposed by dalias the .mo format was designed in a way such that all application can used a single shared non-mutable copy of the translation strings in memory. years later an issue was identified with format string specifier macros that differ between platforms (like PRIu64) and a new syntax introduced: %. this however breaks the non-mutable aspect of the .mo files, since now every application has to remap a modified copy of the strings containing these "sysdep" format specifiers. we simply replace these with all possible expanded values of such a macro directly in the generated .mo file. --- src/msgfmt.c | 114 +++++++++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 103 insertions(+), 11 deletions(-) diff --git a/src/msgfmt.c b/src/msgfmt.c index ab70664..627e106 100644 --- a/src/msgfmt.c +++ b/src/msgfmt.c @@ -94,26 +94,118 @@ int strmap_comp(const void *a_, const void *b_) { return strcmp(cb_for_qsort->strbuffer[0] + a->str.off, cb_for_qsort->strbuffer[0] + b->str.off); } +enum sysdep_types { + st_priu32 = 0, + st_priu64, + st_priumax, + st_max +}; +static const char sysdep_str[][10]={ + [st_priu32] = "\x08", + [st_priu64] = "\x08", + [st_priumax] = "\x09", +}; +static const char sysdep_repl[][8]={ + [st_priu32] = "\x02lu\0u", + [st_priu64] = "\x02lu\0llu", + [st_priumax] = "\x01ju" +}; +static const char *get_repl(enum sysdep_types type, unsigned nr) { + assert(nr < (unsigned)sysdep_repl[type][0]); + const char* p = sysdep_repl[type]+1; + while(nr--) p+=strlen(p)+1; + return p; +} +static void replace(char* text, unsigned textlen, const char* what, const char * with) { + char*p = text; + size_t la = strlen(what), li=strlen(with); + assert(la >= li); + for(p=text;textlen >= la;) { + if(!memcmp(p,what,la)) { + memcpy(p, with, li); + textlen -= la; + memmove(p+li,p+la,textlen+1); + p+=li; + } else { + p++; + textlen--; + } + } +} +static unsigned get_form(enum sysdep_types type, unsigned no, unsigned occurences[st_max]) { + unsigned i,divisor = 1; + for(i=type+1;i=(unsigned)sysdep_str[i][0] && !memcmp(p,sysdep_str[i]+1,sysdep_str[i][0])) { + occurences[i]++; + f=1; + p+=sysdep_str[i][0]; + l-=sysdep_str[i][0]; + break; + } + if(!f) p++,l--; + } + *count = 1; + for(i=0;itype == pe_msgid || info->type == pe_msgstr); + char **sysdeps; + unsigned len, count, i, l; switch(d->pass) { case pass_collect_sizes: - d->num[info->type] += 1; - d->len[info->type] += info->textlen +1; + sysdep_transform(info->text, info->textlen, &len, &count, 1); + d->num[info->type] += count; + d->len[info->type] += len +1; break; case pass_second: - memcpy(d->strbuffer[info->type] + d->stroff[info->type], info->text, info->textlen+1); - if(info->type == pe_msgid) - d->strlist[d->curr[info->type]].str = (struct strtbl){.len=info->textlen, .off=d->stroff[info->type]}; - else { - assert(d->curr[pe_msgid] == d->curr[pe_msgstr]+1); - d->translist[d->curr[info->type]] = (struct strtbl){.len=info->textlen, .off=d->stroff[info->type]}; - d->strlist[d->curr[info->type]].trans = &d->translist[d->curr[info->type]]; + sysdeps = sysdep_transform(info->text, info->textlen, &len, &count, 0); + for(i=0;istrbuffer[info->type] + d->stroff[info->type], sysdeps[i], l+1); + if(info->type == pe_msgid) + d->strlist[d->curr[info->type]].str = (struct strtbl){.len=l, .off=d->stroff[info->type]}; + else { + if(!i) assert(d->curr[pe_msgid] == d->curr[pe_msgstr] + count); + d->translist[d->curr[info->type]] = (struct strtbl){.len=l, .off=d->stroff[info->type]}; + d->strlist[d->curr[info->type]].trans = &d->translist[d->curr[info->type]]; + } + d->curr[info->type]++; + d->stroff[info->type]+=l+1; } - d->curr[info->type]++; - d->stroff[info->type]+=info->textlen+1; + free(sysdeps); break; default: abort(); -- cgit v1.2.1