Skip to content

Commit ee82b15

Browse files
committed
msgfmt: sort strings
closes #6 unfortunately the fail-safe design had to be sacrified, to effectively sort the string table we need to allocate dynamic memory.
1 parent 1f0b51b commit ee82b15

File tree

1 file changed

+55
-40
lines changed

1 file changed

+55
-40
lines changed

src/msgfmt.c

Lines changed: 55 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -59,66 +59,61 @@ const struct mo_hdr def_hdr = {
5959

6060
// pass 0: collect numbers of strings, calculate size and offsets for tables
6161
// print header
62-
// pass 1: print string table [lengths/offsets]
63-
// pass 2: print translation table [lengths/offsets]
64-
// pass 3: print strings
65-
// pass 4: print translations
62+
// pass 1: create in-memory string tables
6663
enum passes {
6764
pass_first = 0,
6865
pass_collect_sizes = pass_first,
6966
pass_second,
70-
pass_print_string_offsets = pass_second,
71-
pass_print_translation_offsets,
72-
pass_print_strings,
73-
pass_print_translations,
7467
pass_max,
7568
};
7669

70+
struct strtbl {
71+
unsigned len, off;
72+
};
73+
74+
struct strmap {
75+
struct strtbl str, *trans;
76+
};
77+
7778
struct callbackdata {
7879
enum passes pass;
7980
unsigned off;
8081
FILE* out;
8182
unsigned num[pe_maxstr];
8283
unsigned len[pe_maxstr];
84+
struct strmap *strlist;
85+
struct strtbl *translist;
86+
char *strbuffer[pe_maxstr];
87+
unsigned stroff[pe_maxstr];
88+
unsigned curr[pe_maxstr];
8389
};
8490

91+
static struct callbackdata *cb_for_qsort;
92+
int strmap_comp(const void *a_, const void *b_) {
93+
const struct strmap *a = a_, *b = b_;
94+
return strcmp(cb_for_qsort->strbuffer[0] + a->str.off, cb_for_qsort->strbuffer[0] + b->str.off);
95+
}
96+
8597

8698
int process_line_callback(struct po_info* info, void* user) {
8799
struct callbackdata *d = (struct callbackdata *) user;
88100
assert(info->type == pe_msgid || info->type == pe_msgstr);
89101
switch(d->pass) {
90102
case pass_collect_sizes:
91103
d->num[info->type] += 1;
92-
d->len[info->type] += info->textlen;
93-
break;
94-
case pass_print_string_offsets:
95-
if(info->type == pe_msgstr) break;
96-
write_offsets:
97-
// print length of current string
98-
fwrite(&info->textlen, sizeof(unsigned), 1, d->out);
99-
// print offset of current string
100-
fwrite(&d->off, sizeof(unsigned), 1, d->out);
101-
d->off += info->textlen + 1;
104+
d->len[info->type] += info->textlen +1;
102105
break;
103-
case pass_print_translation_offsets:
104-
#ifndef DO_NOTHING
105-
if(info->type == pe_msgid) break;
106-
#else
107-
if(info->type != pe_msgid) break;
108-
#endif
109-
goto write_offsets;
110-
case pass_print_strings:
111-
if(info->type == pe_msgstr) break;
112-
write_string:
113-
fwrite(info->text, info->textlen + 1, 1, d->out);
114-
break;
115-
case pass_print_translations:
116-
#ifndef DO_NOTHING
117-
if(info->type == pe_msgid) break;
118-
#else
119-
if(info->type != pe_msgid) break;
120-
#endif
121-
goto write_string;
106+
case pass_second:
107+
memcpy(d->strbuffer[info->type] + d->stroff[info->type], info->text, info->textlen+1);
108+
if(info->type == pe_msgid)
109+
d->strlist[d->curr[info->type]].str = (struct strtbl){.len=info->textlen, .off=d->stroff[info->type]};
110+
else {
111+
assert(d->curr[pe_msgid] == d->curr[pe_msgstr]+1);
112+
d->translist[d->curr[info->type]] = (struct strtbl){.len=info->textlen, .off=d->stroff[info->type]};
113+
d->strlist[d->curr[info->type]].trans = &d->translist[d->curr[info->type]];
114+
}
115+
d->curr[info->type]++;
116+
d->stroff[info->type]+=info->textlen+1;
122117
break;
123118
default:
124119
abort();
@@ -149,19 +144,17 @@ int process(FILE *in, FILE *out) {
149144
int invalid_file = 0;
150145

151146
mohdr.off_tbl_trans = mohdr.off_tbl_org;
152-
for(d.pass = pass_first; d.pass < pass_max; d.pass++) {
147+
for(d.pass = pass_first; d.pass <= pass_second; d.pass++) {
153148
if(d.pass == pass_second) {
154149
// start of second pass:
155150
// check that data gathered in first pass is consistent
156-
#ifndef DO_NOTHING
157151
if(d.num[pe_msgid] != d.num[pe_msgstr]) {
158152
// one should actually abort here,
159153
// but gnu gettext simply writes an empty .mo and returns success.
160154
//abort();
161155
d.num[pe_msgid] = 0;
162156
invalid_file = 1;
163157
}
164-
#endif
165158

166159
// calculate header fields from len and num arrays
167160
mohdr.numstring = d.num[pe_msgid];
@@ -172,6 +165,13 @@ int process(FILE *in, FILE *out) {
172165
// set offset startvalue
173166
d.off = mohdr.off_tbl_trans + d.num[pe_msgid] * (sizeof(unsigned)*2);
174167
if(invalid_file) return 0;
168+
169+
d.strlist = malloc(d.num[pe_msgid] * sizeof(struct strmap));
170+
d.translist = malloc(d.num[pe_msgstr] * sizeof(struct strtbl));
171+
d.strbuffer[pe_msgid] = malloc(d.len[pe_msgid]);
172+
d.strbuffer[pe_msgstr] = malloc(d.len[pe_msgstr]);
173+
d.stroff[pe_msgid] = d.stroff[pe_msgstr] = 0;
174+
assert(d.strlist && d.translist && d.strbuffer[0] && d.strbuffer[1]);
175175
}
176176
poparser_init(p, convbuf, sizeof(convbuf), process_line_callback, &d);
177177

@@ -183,6 +183,21 @@ int process(FILE *in, FILE *out) {
183183

184184
fseek(in, 0, SEEK_SET);
185185
}
186+
187+
cb_for_qsort = &d;
188+
qsort(d.strlist, d.num[pe_msgid], sizeof (struct strmap), strmap_comp);
189+
unsigned i;
190+
for(i = 0; i < d.num[0]; i++) {
191+
d.strlist[i].str.off += d.off;
192+
fwrite(&d.strlist[i].str, sizeof(struct strtbl), 1, d.out);
193+
}
194+
for(i = 0; i < d.num[1]; i++) {
195+
d.strlist[i].trans->off += d.off + d.len[0];
196+
fwrite(d.strlist[i].trans, sizeof(struct strtbl), 1, d.out);
197+
}
198+
fwrite(d.strbuffer[0], d.len[0], 1, d.out);
199+
fwrite(d.strbuffer[1], d.len[1], 1, d.out);
200+
186201
return 0;
187202
}
188203

0 commit comments

Comments
 (0)