1
/* GNU gettext - internationalization aids
2
Copyright (C) 1995-1998, 2000, 2001 Free Software Foundation, Inc.
4
This file was written by Peter Miller <millerp@canb.auug.org.au>
6
This program is free software; you can redistribute it and/or modify
7
it under the terms of the GNU General Public License as published by
8
the Free Software Foundation; either version 2, or (at your option)
11
This program is distributed in the hope that it will be useful,
12
but WITHOUT ANY WARRANTY; without even the implied warranty of
13
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
GNU General Public License for more details.
16
You should have received a copy of the GNU General Public License
17
along with this program; if not, write to the Free Software
18
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
32
/* Prototypes for local functions. */
33
static message_ty *message_list_search_fuzzy_inner PARAMS ((
34
message_list_ty *__mlp, const char *__msgid, double *__best_weight_p));
39
parse_c_format_description_string (s)
42
if (strstr (s, "no-c-format") != NULL)
44
else if (strstr (s, "impossible-c-format") != NULL)
46
else if (strstr (s, "possible-c-format") != NULL)
48
else if (strstr (s, "c-format") != NULL)
55
possible_c_format_p (is_c_format)
56
enum is_c_format is_c_format;
58
return is_c_format == possible || is_c_format == yes;
63
parse_c_width_description_string (s)
66
if (strstr (s, "no-wrap") != NULL)
68
else if (strstr (s, "wrap") != NULL)
75
message_alloc (msgid, msgid_plural)
77
const char *msgid_plural;
81
mp = xmalloc (sizeof (message_ty));
83
mp->msgid_plural = (msgid_plural != NULL ? xstrdup (msgid_plural) : NULL);
85
mp->comment_dot = NULL;
86
mp->filepos_count = 0;
88
mp->variant_count = 0;
93
mp->is_c_format = undecided;
94
mp->do_wrap = undecided;
105
if (mp->comment != NULL)
106
string_list_free (mp->comment);
107
if (mp->comment_dot != NULL)
108
string_list_free (mp->comment_dot);
109
free ((char *) mp->msgid);
110
if (mp->msgid_plural != NULL)
111
free ((char *) mp->msgid_plural);
112
for (j = 0; j < mp->variant_count; ++j)
113
free ((char *) mp->variant[j].msgstr);
114
if (mp->variant != NULL)
116
for (j = 0; j < mp->filepos_count; ++j)
117
free ((char *) mp->filepos[j].file_name);
118
if (mp->filepos != NULL)
125
message_variant_search (mp, domain)
130
message_variant_ty *mvp;
132
for (j = 0; j < mp->variant_count; ++j)
134
mvp = &mp->variant[j];
135
if (0 == strcmp (domain, mvp->domain))
143
message_variant_append (mp, domain, msgstr, msgstr_len, pp)
148
const lex_pos_ty *pp;
151
message_variant_ty *mvp;
153
nbytes = (mp->variant_count + 1) * sizeof (mp->variant[0]);
154
mp->variant = xrealloc (mp->variant, nbytes);
155
mvp = &mp->variant[mp->variant_count++];
156
mvp->domain = domain;
157
mvp->msgstr = msgstr;
158
mvp->msgstr_len = msgstr_len;
164
message_comment_append (mp, s)
168
if (mp->comment == NULL)
169
mp->comment = string_list_alloc ();
170
string_list_append (mp->comment, s);
175
message_comment_dot_append (mp, s)
179
if (mp->comment_dot == NULL)
180
mp->comment_dot = string_list_alloc ();
181
string_list_append (mp->comment_dot, s);
192
result = message_alloc (xstrdup (mp->msgid), mp->msgid_plural);
194
for (j = 0; j < mp->variant_count; ++j)
196
message_variant_ty *mvp = &mp->variant[j];
197
message_variant_append (result, mvp->domain, mvp->msgstr, mvp->msgstr_len,
202
for (j = 0; j < mp->comment->nitems; ++j)
203
message_comment_append (result, mp->comment->item[j]);
207
for (j = 0; j < mp->comment_dot->nitems; ++j)
208
message_comment_dot_append (result, mp->comment_dot->item[j]);
210
result->is_fuzzy = mp->is_fuzzy;
211
result->is_c_format = mp->is_c_format;
212
result->do_wrap = mp->do_wrap;
213
for (j = 0; j < mp->filepos_count; ++j)
215
lex_pos_ty *pp = &mp->filepos[j];
216
message_comment_filepos (result, pp->file_name, pp->line_number);
223
message_merge (def, ref)
228
const char *pot_date_ptr = NULL;
229
size_t pot_date_len = 0;
232
/* Take the msgid from the reference. When fuzzy matches are made,
233
the definition will not be unique, but the reference will be -
234
usually because it has a typo. */
235
result = message_alloc (xstrdup (ref->msgid), ref->msgid_plural);
237
/* If msgid is the header entry (i.e., "") we find the
238
POT-Creation-Date line in the reference. */
239
if (ref->msgid[0] == '\0')
241
pot_date_ptr = strstr (ref->variant[0].msgstr, "POT-Creation-Date:");
242
if (pot_date_ptr != NULL)
246
pot_date_ptr += sizeof ("POT-Creation-Date:") - 1;
248
endp = strchr (pot_date_ptr, '\n');
252
endp = strchr (pot_date_ptr, '\0');
253
pot_date_len = (endp - pot_date_ptr) + 1;
254
extended = (char *) alloca (pot_date_len + 1);
255
stpcpy (stpcpy (extended, pot_date_ptr), "\n");
256
pot_date_ptr = extended;
259
pot_date_len = (endp - pot_date_ptr) + 1;
261
if (pot_date_len == 0)
266
/* Take the variant list from the definition. The msgstr of the
267
refences will be empty, as they were generated by xgettext. If
268
we currently process the header entry we have to merge the msgstr
269
by using the POT-Creation-Date field from the .pot file. */
270
for (j = 0; j < def->variant_count; ++j)
272
message_variant_ty *mvp = &def->variant[j];
274
if (ref->msgid[0] == '\0')
276
/* Oh, oh. The header entry and we have something to fill in. */
283
{ "Project-Id-Version:", sizeof ("Project-Id-Version:") - 1 },
285
{ "POT-Creation-Date:", sizeof ("POT-Creation-Date:") - 1 },
286
#define POT_CREATION 1
287
{ "PO-Revision-Date:", sizeof ("PO-Revision-Date:") - 1 },
288
#define PO_REVISION 2
289
{ "Last-Translator:", sizeof ("Last-Translator:") - 1 },
290
#define LAST_TRANSLATOR 3
291
{ "Language-Team:", sizeof ("Language-Team:") - 1 },
292
#define LANGUAGE_TEAM 4
293
{ "MIME-Version:", sizeof ("MIME-Version:") - 1 },
294
#define MIME_VERSION 5
295
{ "Content-Type:", sizeof ("Content-Type:") - 1 },
296
#define CONTENT_TYPE 6
297
{ "Content-Transfer-Encoding:",
298
sizeof ("Content-Transfer-Encoding:") - 1 }
299
#define CONTENT_TRANSFER 7
306
} header_fields[UNKNOWN + 1];
311
/* Clear all fields. */
312
memset (header_fields, '\0', sizeof (header_fields));
317
const char *endp = strchr (cp, '\n');
318
int terminated = endp != NULL;
323
endp = strchr (cp, '\0');
327
copy = (char *) alloca (len + 1);
328
stpcpy (stpcpy (copy, cp), "\n");
333
len = (endp - cp) + 1;
337
/* Compare with any of the known fields. */
339
cnt < sizeof (known_fields) / sizeof (known_fields[0]);
341
if (strncasecmp (cp, known_fields[cnt].name,
342
known_fields[cnt].len) == 0)
345
if (cnt < sizeof (known_fields) / sizeof (known_fields[0]))
347
header_fields[cnt].string = &cp[known_fields[cnt].len];
348
header_fields[cnt].len = len - known_fields[cnt].len;
352
/* It's an unknown field. Append content to what is
354
char *extended = (char *) alloca (header_fields[UNKNOWN].len
356
memcpy (extended, header_fields[UNKNOWN].string,
357
header_fields[UNKNOWN].len);
358
memcpy (&extended[header_fields[UNKNOWN].len], cp, len);
359
extended[header_fields[UNKNOWN].len + len] = '\0';
360
header_fields[UNKNOWN].string = extended;
361
header_fields[UNKNOWN].len += len;
367
if (pot_date_ptr != NULL)
369
header_fields[POT_CREATION].string = pot_date_ptr;
370
header_fields[POT_CREATION].len = pot_date_len;
373
/* Concatenate all the various fields. */
375
for (cnt = 0; cnt < UNKNOWN; ++cnt)
376
if (header_fields[cnt].string != NULL)
377
len += known_fields[cnt].len + header_fields[cnt].len;
378
len += header_fields[UNKNOWN].len;
380
cp = newp = (char *) xmalloc (len + 1);
383
#define IF_FILLED(idx) \
384
if (header_fields[idx].string) \
385
newp = stpncpy (stpcpy (newp, known_fields[idx].name), \
386
header_fields[idx].string, header_fields[idx].len)
388
IF_FILLED (PROJECT_ID);
389
IF_FILLED (POT_CREATION);
390
IF_FILLED (PO_REVISION);
391
IF_FILLED (LAST_TRANSLATOR);
392
IF_FILLED (LANGUAGE_TEAM);
393
IF_FILLED (MIME_VERSION);
394
IF_FILLED (CONTENT_TYPE);
395
IF_FILLED (CONTENT_TRANSFER);
396
if (header_fields[UNKNOWN].string != NULL)
397
stpcpy (newp, header_fields[UNKNOWN].string);
399
message_variant_append (result, mvp->domain, cp, strlen (cp) + 1,
403
message_variant_append (result, mvp->domain, mvp->msgstr,
404
mvp->msgstr_len, &mvp->pos);
407
/* Take the comments from the definition file. There will be none at
408
all in the reference file, as it was generated by xgettext. */
410
for (j = 0; j < def->comment->nitems; ++j)
411
message_comment_append (result, def->comment->item[j]);
413
/* Take the dot comments from the reference file, as they are
414
generated by xgettext. Any in the definition file are old ones
415
collected by previous runs of xgettext and msgmerge. */
416
if (ref->comment_dot)
417
for (j = 0; j < ref->comment_dot->nitems; ++j)
418
message_comment_dot_append (result, ref->comment_dot->item[j]);
420
/* The flags are mixed in a special way. Some informations come
421
from the reference message (such as format/no-format), others
422
come from the definition file (fuzzy or not). */
423
result->is_fuzzy = def->is_fuzzy;
424
result->is_c_format = ref->is_c_format;
425
result->do_wrap = ref->do_wrap;
427
/* Take the file position comments from the reference file, as they
428
are generated by xgettext. Any in the definition file are old ones
429
collected by previous runs of xgettext and msgmerge. */
430
for (j = 0; j < ref->filepos_count; ++j)
432
lex_pos_ty *pp = &ref->filepos[j];
433
message_comment_filepos (result, pp->file_name, pp->line_number);
436
/* All done, return the merged message to the caller. */
442
message_comment_filepos (mp, name, line)
452
/* See if we have this position already. They are kept in sorted
453
order, so use a binary chop. */
454
/* FIXME: use bsearch */
456
max = (int) mp->filepos_count - 1;
462
mid = (min + max) / 2;
463
pp = &mp->filepos[mid];
464
cmp = strcmp (pp->file_name, name);
466
cmp = (int) pp->line_number - line;
475
/* Extend the list so that we can add an position to it. */
476
nbytes = (mp->filepos_count + 1) * sizeof (mp->filepos[0]);
477
mp->filepos = xrealloc (mp->filepos, nbytes);
479
/* Shuffle the rest of the list up one, so that we can insert the
480
position at ``min''. */
481
/* FIXME: use memmove */
482
for (j = mp->filepos_count; j > min; --j)
483
mp->filepos[j] = mp->filepos[j - 1];
486
/* Insert the postion into the empty slot. */
487
pp = &mp->filepos[min];
488
pp->file_name = xstrdup (name);
489
pp->line_number = line;
494
message_list_alloc ()
496
message_list_ty *mlp;
498
mlp = xmalloc (sizeof (message_list_ty));
507
message_list_append (mlp, mp)
508
message_list_ty *mlp;
511
if (mlp->nitems >= mlp->nitems_max)
515
mlp->nitems_max = mlp->nitems_max * 2 + 4;
516
nbytes = mlp->nitems_max * sizeof (message_ty *);
517
mlp->item = xrealloc (mlp->item, nbytes);
519
mlp->item[mlp->nitems++] = mp;
524
message_list_delete_nth (mlp, n)
525
message_list_ty *mlp;
530
if (n >= mlp->nitems)
532
message_free (mlp->item[n]);
533
for (j = n + 1; j < mlp->nitems; ++j)
534
mlp->item[j - 1] = mlp->item[j];
540
message_list_search (mlp, msgid)
541
message_list_ty *mlp;
546
for (j = 0; j < mlp->nitems; ++j)
551
if (0 == strcmp (msgid, mp->msgid))
559
message_list_search_fuzzy_inner (mlp, msgid, best_weight_p)
560
message_list_ty *mlp;
562
double *best_weight_p;
568
for (j = 0; j < mlp->nitems; ++j)
576
for (k = 0; k < mp->variant_count; ++k)
577
if (mp->variant[k].msgstr != NULL && mp->variant[k].msgstr[0] != '\0')
579
if (k >= mp->variant_count)
582
weight = fstrcmp (msgid, mp->msgid);
583
if (weight > *best_weight_p)
585
*best_weight_p = weight;
594
message_list_search_fuzzy (mlp, msgid)
595
message_list_ty *mlp;
601
return message_list_search_fuzzy_inner (mlp, msgid, &best_weight);
606
message_list_free (mlp)
607
message_list_ty *mlp;
611
for (j = 0; j < mlp->nitems; ++j)
612
message_free (mlp->item[j]);
619
message_list_list_ty *
620
message_list_list_alloc ()
622
message_list_list_ty *mllp;
624
mllp = xmalloc (sizeof (message_list_list_ty));
626
mllp->nitems_max = 0;
633
message_list_list_append (mllp, mlp)
634
message_list_list_ty *mllp;
635
message_list_ty *mlp;
637
if (mllp->nitems >= mllp->nitems_max)
641
mllp->nitems_max = mllp->nitems_max * 2 + 4;
642
nbytes = mllp->nitems_max * sizeof (message_list_ty *);
643
mllp->item = xrealloc (mllp->item, nbytes);
645
mllp->item[mllp->nitems++] = mlp;
650
message_list_list_append_list (mllp, mllp2)
651
message_list_list_ty *mllp;
652
message_list_list_ty *mllp2;
656
for (j = 0; j < mllp2->nitems; ++j)
657
message_list_list_append (mllp, mllp2->item[j]);
662
message_list_list_search (mllp, msgid)
663
message_list_list_ty *mllp;
668
for (j = 0; j < mllp->nitems; ++j)
670
message_list_ty *mlp;
674
mp = message_list_search (mlp, msgid);
683
message_list_list_search_fuzzy (mllp, msgid)
684
message_list_list_ty *mllp;
693
for (j = 0; j < mllp->nitems; ++j)
695
message_list_ty *mlp;
699
mp = message_list_search_fuzzy_inner (mlp, msgid, &best_weight);
708
message_list_list_free (mllp)
709
message_list_list_ty *mllp;
713
for (j = 0; j < mllp->nitems; ++j)
714
message_list_free (mllp->item[j]);