diff options
author | xhe <xw897002528@gmail.com> | 2017-05-01 12:47:40 +0800 |
---|---|---|
committer | xhe <xw897002528@gmail.com> | 2017-05-06 13:03:23 +0800 |
commit | d1bd158eb7463967ab3dd9a862e14d114523d37b (patch) | |
tree | 5e90c92211151f437b3aa33c467652b65e3d9798 | |
parent | ffa22a010fbbf330c5c8de41077f36415c16d38a (diff) | |
download | gettext-tiny-d1bd158eb7463967ab3dd9a862e14d114523d37b.tar.gz |
add support for msgctxt
-rw-r--r-- | src/msgfmt.c | 251 | ||||
-rw-r--r-- | src/poparser.c | 24 | ||||
-rw-r--r-- | src/poparser.h | 1 |
3 files changed, 172 insertions, 104 deletions
diff --git a/src/msgfmt.c b/src/msgfmt.c index 48b9f4c..d92274a 100644 --- a/src/msgfmt.c +++ b/src/msgfmt.c @@ -79,6 +79,23 @@ struct callbackdata { enum passes pass; unsigned off; FILE* out; + char msgidbuf1[4096]; + unsigned milen1; + char msgidbuf2[4096]; + unsigned milen2; + char pluralbuf1[4096]; + unsigned pllen1; + char pluralbuf2[4096]; + unsigned pllen2; + char msgctxtbuf[4096]; + unsigned ctxtlen; + char msgstrbuf1[4096]; + unsigned mslen1; + char msgstrbuf2[4096]; + unsigned mslen2; + unsigned msc; + unsigned priv_type; + unsigned priv_len; unsigned num[pe_maxstr]; unsigned len[pe_maxstr]; struct strmap *strlist; @@ -101,14 +118,6 @@ enum sysdep_types { st_max }; -static char msgidbuf[1024]; -static unsigned idlen[3] = { 0 }; -static char msgstr1[4096]; -static unsigned mslen1=0; -static char msgstr2[4096]; -static unsigned mslen2=0; -static unsigned msc=0; - static const char sysdep_str[][10]={ [st_priu32] = "\x08<PRIu32>", [st_priu64] = "\x08<PRIu64>", @@ -193,124 +202,157 @@ static void error(const char* msg) { exit(1); } -static inline void write_plurals(struct callbackdata *d) { - d->translist[d->curr[pe_msgstr]].len=mslen1-1; - d->translist[d->curr[pe_msgstr]].off=d->stroff[pe_msgstr]; - d->strlist[d->curr[pe_msgstr]].trans = &d->translist[d->curr[pe_msgstr]]; - - memcpy(d->strbuffer[pe_msgstr] + d->stroff[pe_msgstr], msgstr1, mslen1); - d->stroff[pe_msgstr]+=mslen1; - d->curr[pe_msgstr]++; +static inline void writemsg(struct callbackdata *d) { + if(d->milen1 != 0) { + if(!d->strlist[d->curr[pe_msgid]].str.off) + d->strlist[d->curr[pe_msgid]].str.off=d->stroff[pe_msgid]; - d->translist[d->curr[pe_msgstr]].len=mslen2-1; - d->translist[d->curr[pe_msgstr]].off=d->stroff[pe_msgstr]; - d->strlist[d->curr[pe_msgstr]].trans = &d->translist[d->curr[pe_msgstr]]; - - memcpy(d->strbuffer[pe_msgstr] + d->stroff[pe_msgstr], msgstr2, mslen2); - d->stroff[pe_msgstr]+=mslen2; - d->curr[pe_msgstr]++; + if(d->ctxtlen != 0) { + memcpy(d->strbuffer[pe_msgid] + d->stroff[pe_msgid], d->msgctxtbuf, d->ctxtlen); + d->strlist[d->curr[pe_msgid]].str.len+=d->ctxtlen; + d->stroff[pe_msgid]+=d->ctxtlen; + } + memcpy(d->strbuffer[pe_msgid] + d->stroff[pe_msgid], d->msgidbuf1, d->milen1); + d->stroff[pe_msgid]+=d->milen1; + d->strlist[d->curr[pe_msgid]].str.len+=d->milen1-1; + if(d->pllen1 != 0) { + memcpy(d->strbuffer[pe_msgid] + d->stroff[pe_msgid], d->pluralbuf1, d->pllen1); + d->strlist[d->curr[pe_msgid]].str.len+=d->pllen1; + d->stroff[pe_msgid]+=d->pllen1; + } + d->curr[pe_msgid]++; + } + if(d->milen2 != 0) { + if(!d->strlist[d->curr[pe_msgid]].str.off) + d->strlist[d->curr[pe_msgid]].str.off=d->stroff[pe_msgid]; + + if(d->ctxtlen != 0) { + memcpy(d->strbuffer[pe_msgid] + d->stroff[pe_msgid], d->msgctxtbuf, d->ctxtlen); + d->strlist[d->curr[pe_msgid]].str.len+=d->ctxtlen; + d->stroff[pe_msgid]+=d->ctxtlen; + } + memcpy(d->strbuffer[pe_msgid] + d->stroff[pe_msgid], d->msgidbuf2, d->milen2); + d->stroff[pe_msgid]+=d->milen2; + d->strlist[d->curr[pe_msgid]].str.len+=d->milen2-1; + if(d->pllen2 != 0) { + memcpy(d->strbuffer[pe_msgid] + d->stroff[pe_msgid], d->pluralbuf2, d->pllen2); + d->strlist[d->curr[pe_msgid]].str.len+=d->pllen2; + d->stroff[pe_msgid]+=d->pllen2; + } + d->curr[pe_msgid]++; + } - mslen1=mslen2=msc=0; + d->pllen2=d->pllen1=d->ctxtlen=d->milen1=d->milen2=0; } -static inline void dinvalid(struct callbackdata *d, struct po_info *info) { - // previous group of msgid/str is invalid - if(d->curr[pe_msgid] > 1 && d->translist[d->curr[pe_msgstr]-1].len == 0) { - // set back the buffer len +static inline void writestr(struct callbackdata *d, struct po_info *info) { + // msgid xx; msgstr ""; is widely happened, it's invalid + if(d->curr[pe_msgstr] + // we do not check the 1st msgid/str + && ((d->curr[pe_msgid] - d->curr[pe_msgstr]) == 0) + // in case curr[id] - curr[str] = 2(when sysdeps), .len == 0 is always true + && d->translist[d->curr[pe_msgstr]-1].len == 0) { + // str empty, invalid, set back everything, so they will be overrided + d->len[pe_msgid] -= d->strlist[d->curr[pe_msgstr]-1].str.len + 1; - d->len[pe_msgstr] -= d->translist[d->curr[pe_msgstr]-1].len + 1; - // set back the offset + d->strlist[d->curr[pe_msgstr]-1].str.len=0; + d->len[pe_msgstr]--; d->stroff[pe_msgid] = d->strlist[d->curr[pe_msgstr]-1].str.off; d->stroff[pe_msgstr] = d->translist[d->curr[pe_msgstr]-1].off; - - // kick the invalid out of counts d->num[pe_msgid]--; d->curr[pe_msgid]--; - d->num[pe_msgstr] -= d->translist[d->curr[pe_msgstr]-1].len + 1; - d->curr[pe_msgstr] -= d->translist[d->curr[pe_msgstr]-1].len + 1; + d->num[pe_msgstr]--; + d->curr[pe_msgstr]--; + d->mslen1=d->mslen2=d->msc=0; + return; + } + + if(d->msc && d->msc <= info->nplurals) { + // plural <= nplurals is allowed + d->translist[d->curr[pe_msgstr]].len=d->mslen1-1; + d->translist[d->curr[pe_msgstr]].off=d->stroff[pe_msgstr]; + d->strlist[d->curr[pe_msgstr]].trans = &d->translist[d->curr[pe_msgstr]]; + + memcpy(d->strbuffer[pe_msgstr] + d->stroff[pe_msgstr], d->msgstrbuf1, d->mslen1); + d->stroff[pe_msgstr]+=d->mslen1; + d->curr[pe_msgstr]++; + + if(d->mslen2 != 0) { + d->translist[d->curr[pe_msgstr]].len=d->mslen2-1; + d->translist[d->curr[pe_msgstr]].off=d->stroff[pe_msgstr]; + d->strlist[d->curr[pe_msgstr]].trans = &d->translist[d->curr[pe_msgstr]]; + + memcpy(d->strbuffer[pe_msgstr] + d->stroff[pe_msgstr], d->msgstrbuf2, d->mslen2); + d->stroff[pe_msgstr]+=d->mslen2; + d->curr[pe_msgstr]++; + } + + d->mslen1=d->mslen2=d->msc=0; } - // plural <= nplurals is allowed - if(msc && msc <= info->nplurals) - write_plurals(d); } int process_line_callback(struct po_info* info, void* user) { struct callbackdata *d = (struct callbackdata *) user; - assert(info->type == pe_msgid || info->type == pe_msgstr || info->type == pe_plural); + assert(info->type == pe_msgid || info->type == pe_ctxt || info->type == pe_msgstr || info->type == pe_plural); char **sysdeps; unsigned len, count, i, l; switch(d->pass) { case pass_collect_sizes: sysdep_transform(info->text, info->textlen, &len, &count, 1); d->num[info->type] += count; + if(info->type == pe_msgid && count == 2 && d->priv_type == pe_ctxt) { + // ctxt meets msgid with sysdeps, multiply num and len to suit it + d->len[pe_ctxt] += d->priv_len +1; + d->num[pe_ctxt]++; + } + if(count != 1 && info->type == pe_ctxt) { + // except msgid, str, plural, all other types should not have sysdeps + abort(); + } + + d->priv_type = info->type; + d->priv_len = len; d->len[info->type] += len +1; break; case pass_second: sysdeps = sysdep_transform(info->text, info->textlen, &len, &count, 0); - // we may met %<PRIu32> in plurals - unsigned pc = d->curr[pe_msgid] - d->curr[pe_msgstr]; - if(pc == 2 && info->type == pe_plural) { - // extract len and off infomation - // bakup the content of msgid - for(unsigned a=pc;a>0;a--) { - idlen[a-1] = d->strlist[d->curr[pe_msgid]-a].str.len + 1; - memcpy(&msgidbuf[idlen[a]], d->strbuffer[pe_msgid] + d->strlist[d->curr[pe_msgid]-a].str.off, idlen[a-1]); - - } - // rollback the offset - d->stroff[pe_msgid]= d->strlist[d->curr[pe_msgid]-pc].str.off; - } for(i=0;i<count;i++) { l = strlen(sysdeps[i]); if(info->type == pe_msgid) { - // check for previous group of msgid/str - dinvalid(d, info); - d->strlist[d->curr[pe_msgid]].str.len=l; - d->strlist[d->curr[pe_msgid]].str.off=d->stroff[pe_msgid]; - d->curr[pe_msgid]++; - memcpy(d->strbuffer[pe_msgid] + d->stroff[pe_msgid], sysdeps[i], l+1); - d->stroff[pe_msgid]+=l+1; + // after str, it's msgid or msgctxt + writestr(d, info); + // just copy, it's written down when writemsg() + if(i==0) { + memcpy(d->msgidbuf1, sysdeps[i], l+1); + d->milen1 = l+1; + } else { + memcpy(d->msgidbuf2, sysdeps[i], l+1); + d->milen2 = l+1; + } } else if(info->type == pe_plural) { - if(pc != 2) { - // should not count on msg_idplural - memcpy(d->strbuffer[pe_msgid] + d->stroff[pe_msgid], sysdeps[i], l+1); - d->strlist[d->curr[pe_msgid]-1].str.len+=l+1; - d->stroff[pe_msgid]+=l+1; + if(i==0) { + memcpy(d->pluralbuf1, sysdeps[i], l+1); + d->pllen1 = l+1; } else { - d->strlist[d->curr[pe_msgid]-(count-i)].str.len = idlen[(count-i)-1]-1 + l+1; - d->strlist[d->curr[pe_msgid]-(count-i)].str.off = d->stroff[pe_msgid]; - - memcpy(d->strbuffer[pe_msgid] + d->stroff[pe_msgid], &msgidbuf[idlen[(count-i)]], idlen[(count-i)-1]); - d->stroff[pe_msgid]+=idlen[(count-i)-1]; - - memcpy(d->strbuffer[pe_msgid] + d->stroff[pe_msgid], sysdeps[i], l+1); - d->stroff[pe_msgid]+=l+1; + memcpy(d->pluralbuf2, sysdeps[i], l+1); + d->pllen2 = l+1; } + } else if(info->type == pe_ctxt) { + writestr(d, info); + d->ctxtlen = l+1; + memcpy(d->msgctxtbuf, sysdeps[i], l); + d->msgctxtbuf[l] = 0x4;//EOT } else { - if(pc == 1) { - // all one-shot - d->translist[d->curr[pe_msgstr]].len=l; - d->translist[d->curr[pe_msgstr]].off=d->stroff[pe_msgstr]; - d->strlist[d->curr[pe_msgstr]].trans = &d->translist[d->curr[pe_msgstr]]; - d->curr[pe_msgstr]++; - memcpy(d->strbuffer[pe_msgstr] + d->stroff[pe_msgstr], sysdeps[i], l+1); - d->stroff[pe_msgstr]+=l+1; - } else if(pc == 0 ) { - d->translist[d->curr[pe_msgstr]-1].len+=l+1; - memcpy(d->strbuffer[pe_msgstr] + d->stroff[pe_msgstr], sysdeps[i], l+1); - d->stroff[pe_msgstr]+=l+1; + writemsg(d); + // just copy, it's written down when writestr() + if(i==0) { + memcpy(&d->msgstrbuf1[d->mslen1], sysdeps[i], l+1); + d->mslen1 += l+1; + d->msc++; } else { - if(i==0) { - memcpy(&msgstr1[mslen1], sysdeps[i], l+1); - mslen1 += l+1; - } else { - memcpy(&msgstr2[mslen2], sysdeps[i], l+1); - mslen2 += l+1; - msc++; - } - // time to write down - if(msc == info->nplurals) - write_plurals(d); + // sysdeps exist + memcpy(&d->msgstrbuf2[d->mslen2], sysdeps[i], l+1); + d->mslen2 += l+1; } } } @@ -332,15 +374,25 @@ int process(FILE *in, FILE *out) { [pe_msgid] = 0, [pe_msgstr] = 0, [pe_plural] = 0, + [pe_ctxt] = 0, }, .len = { [pe_msgid] = 0, [pe_msgstr] = 0, [pe_plural] = 0, + [pe_ctxt] = 0, }, .off = 0, .out = out, .pass = pass_first, + .ctxtlen = 0, + .pllen1 = 0, + .pllen2 = 0, + .milen1 = 0, + .milen2 = 0, + .mslen1 = 0, + .mslen2 = 0, + .msc = 0, }; struct po_parser pb, *p = &pb; @@ -360,8 +412,8 @@ int process(FILE *in, FILE *out) { } d.strlist = calloc(d.num[pe_msgid] * sizeof(struct strmap), 1); - d.translist = calloc(d.num[pe_msgid] * sizeof(struct strtbl), 1); - d.strbuffer[pe_msgid] = calloc(d.len[pe_msgid]+d.len[pe_plural], 1); + d.translist = calloc(d.num[pe_msgstr] * sizeof(struct strtbl), 1); + d.strbuffer[pe_msgid] = calloc(d.len[pe_msgid]+d.len[pe_plural]+d.len[pe_ctxt], 1); d.strbuffer[pe_msgstr] = calloc(d.len[pe_msgstr], 1); d.stroff[pe_msgid] = d.stroff[pe_msgstr] = 0; assert(d.strlist && d.translist && d.strbuffer[pe_msgid] && d.strbuffer[pe_msgstr]); @@ -373,8 +425,7 @@ int process(FILE *in, FILE *out) { poparser_feed_line(p, lp, sizeof(line)); } poparser_finish(p); - // check for previous group of msgid/str - dinvalid(&d, &p->info); + writestr(&d, &p->info); if(d.pass == pass_second) { // calculate header fields from len and num arrays @@ -398,10 +449,10 @@ int process(FILE *in, FILE *out) { fwrite(&d.strlist[i].str, sizeof(struct strtbl), 1, d.out); } for(i = 0; i < d.num[pe_msgid]; i++) { - d.strlist[i].trans->off += d.off + d.len[pe_msgid] + d.len[pe_plural]; + d.strlist[i].trans->off += d.off + d.len[pe_msgid] + d.len[pe_plural] + d.len[pe_ctxt]; fwrite(d.strlist[i].trans, sizeof(struct strtbl), 1, d.out); } - fwrite(d.strbuffer[pe_msgid], d.len[pe_msgid]+d.len[pe_plural], 1, d.out); + fwrite(d.strbuffer[pe_msgid], d.len[pe_msgid]+d.len[pe_plural]+d.len[pe_ctxt], 1, d.out); fwrite(d.strbuffer[pe_msgstr], d.len[pe_msgstr], 1, d.out); return 0; diff --git a/src/poparser.c b/src/poparser.c index 3e257eb..2d4bcef 100644 --- a/src/poparser.c +++ b/src/poparser.c @@ -30,6 +30,8 @@ static enum po_entry get_type_and_start(struct po_info *info, char* lp, char* en result_type = pe_msgid; else if ((x = strstarts(y, "id_plural")) && isspace(*x)) result_type = pe_plural; + else if ((x = strstarts(y, "ctxt")) && isspace(*x)) + result_type = pe_ctxt; else if ((x = strstarts(y, "str")) && (isspace(*x) || (x[0] == '[' && (x[1]-0x30) < info->nplurals && x[2] == ']' && (x += 3) && isspace(*x)))) result_type = pe_msgstr; @@ -121,6 +123,7 @@ int poparser_feed_line(struct po_parser *p, char* line, size_t buflen) { [pe_str] = { [pe_str] = la_abort, [pe_msgid] = la_abort, + [pe_ctxt] = la_abort, [pe_plural] = la_abort, [pe_msgstr] = la_abort, [pe_invalid] = la_abort, @@ -128,13 +131,23 @@ int poparser_feed_line(struct po_parser *p, char* line, size_t buflen) { [pe_msgid] = { [pe_str] = la_incr, [pe_msgid] = la_abort, + [pe_ctxt] = la_abort, [pe_plural] = la_proc, [pe_msgstr] = la_proc, [pe_invalid] = la_proc, }, + [pe_ctxt] = { + [pe_str] = la_incr, + [pe_msgid] = la_proc, + [pe_ctxt] = la_abort, + [pe_plural] = la_abort, + [pe_msgstr] = la_abort, + [pe_invalid] = la_proc, + }, [pe_plural] = { [pe_str] = la_incr, [pe_msgid] = la_abort, + [pe_ctxt] = la_abort, [pe_plural] = la_abort, [pe_msgstr] = la_proc, [pe_invalid] = la_proc, @@ -142,14 +155,16 @@ int poparser_feed_line(struct po_parser *p, char* line, size_t buflen) { [pe_msgstr] = { [pe_str] = la_incr, [pe_msgid] = la_proc, + [pe_ctxt] = la_abort, [pe_plural] = la_abort, [pe_msgstr] = la_proc, [pe_invalid] = la_proc, }, [pe_invalid] = { - [pe_str] = la_nop, // this can happen when we have msgstr[2] "" ... "foo", since we only parse msgstr[0] and [1] + [pe_str] = la_abort, [pe_msgid] = la_incr, - [pe_plural] = la_abort, + [pe_ctxt] = la_incr, + [pe_plural] = la_incr, [pe_msgstr] = la_incr, [pe_invalid] = la_nop, }, @@ -159,16 +174,17 @@ int poparser_feed_line(struct po_parser *p, char* line, size_t buflen) { type = get_type_and_start(&p->info, line, line + buflen, &strstart); if(fuzzymark) { + if(type == pe_ctxt && fuzzymark == 1) fuzzymark--; if(type == pe_msgid) fuzzymark--; if(fuzzymark > 0) return 0; } switch(action_tbl[p->prev_type][type]) { case la_incr: - assert(type == pe_msgid || type == pe_msgstr || type == pe_str || type == pe_plural); + assert(type == pe_msgid || type == pe_msgstr || type == pe_str || type == pe_plural || pe_ctxt); p->curr_len += get_length_and_convert(&p->info, line + strstart, line + buflen, convbuf + p->curr_len, convbuflen - p->curr_len); break; case la_proc: - assert(p->prev_type == pe_msgid || p->prev_type == pe_msgstr || p->prev_type == pe_plural); + assert(p->prev_type == pe_msgid || p->prev_type == pe_msgstr || p->prev_type == pe_plural || p->prev_type == pe_ctxt); p->info.text = convbuf; p->info.textlen = p->curr_len; p->info.type = p->prev_type; diff --git a/src/poparser.h b/src/poparser.h index 0e2515b..dfe6107 100644 --- a/src/poparser.h +++ b/src/poparser.h @@ -5,6 +5,7 @@ enum po_entry { pe_msgid = 0, pe_plural, + pe_ctxt, pe_msgstr, pe_maxstr, pe_str = pe_maxstr, |