1 diff -urN --exclude Makefile.in --exclude ltconfig --exclude ltmain.sh --exclude configure --exclude build --exclude CVS --exclude config.* --exclude genpatch --exclude .cvsignore --exclude aclocal.m4 --exclude *.po --exclude *.gmo --exclude gettext-0.10.35-hacks.patch gettext.initial/Makefile.am gettext.hacked/Makefile.am
2 --- gettext.initial/Makefile.am Mon Feb 22 13:40:47 1999
3 +++ gettext.hacked/Makefile.am Mon Feb 22 14:10:19 1999
6 AUTOMAKE_OPTIONS = 1.3 gnits
8 -ACLOCAL_AMFLAGS = -I m4
9 +ACLOCAL_AMFLAGS = --acdir=m4 --acdir=$(shell aclocal --print-ac-dir)
11 gettextsrcdir = $(datadir)/gettext
12 gettextsrc_DATA = ABOUT-NLS
13 diff -urN --exclude Makefile.in --exclude ltconfig --exclude ltmain.sh --exclude configure --exclude build --exclude CVS --exclude config.* --exclude genpatch --exclude .cvsignore --exclude aclocal.m4 --exclude *.po --exclude *.gmo --exclude gettext-0.10.35-hacks.patch gettext.initial/configure.in gettext.hacked/configure.in
14 --- gettext.initial/configure.in Mon Feb 22 13:40:47 1999
15 +++ gettext.hacked/configure.in Mon Feb 22 14:10:20 1999
24 dnl Checks for libraries.
25 diff -urN --exclude Makefile.in --exclude ltconfig --exclude ltmain.sh --exclude configure --exclude build --exclude CVS --exclude config.* --exclude genpatch --exclude .cvsignore --exclude aclocal.m4 --exclude *.po --exclude *.gmo --exclude gettext-0.10.35-hacks.patch gettext.initial/doc/stamp-vti gettext.hacked/doc/stamp-vti
26 --- gettext.initial/doc/stamp-vti Mon Feb 22 13:40:47 1999
27 +++ gettext.hacked/doc/stamp-vti Mon Apr 19 18:54:47 1999
29 -@set UPDATED 30 April 1998
30 +@set UPDATED 21 March 1999
33 diff -urN --exclude Makefile.in --exclude ltconfig --exclude ltmain.sh --exclude configure --exclude build --exclude CVS --exclude config.* --exclude genpatch --exclude .cvsignore --exclude aclocal.m4 --exclude *.po --exclude *.gmo --exclude gettext-0.10.35-hacks.patch gettext.initial/doc/version.texi gettext.hacked/doc/version.texi
34 --- gettext.initial/doc/version.texi Mon Feb 22 13:40:47 1999
35 +++ gettext.hacked/doc/version.texi Mon Apr 19 18:54:47 1999
37 -@set UPDATED 30 April 1998
38 +@set UPDATED 21 March 1999
41 diff -urN --exclude Makefile.in --exclude ltconfig --exclude ltmain.sh --exclude configure --exclude build --exclude CVS --exclude config.* --exclude genpatch --exclude .cvsignore --exclude aclocal.m4 --exclude *.po --exclude *.gmo --exclude gettext-0.10.35-hacks.patch gettext.initial/po/gettext.pot gettext.hacked/po/gettext.pot
42 --- gettext.initial/po/gettext.pot Mon Feb 22 13:40:48 1999
43 +++ gettext.hacked/po/gettext.pot Thu May 6 17:32:13 1999
47 "Project-Id-Version: PACKAGE VERSION\n"
48 -"POT-Creation-Date: 1998-04-30 22:50-0700\n"
49 +"POT-Creation-Date: 1999-05-05 18:24-0400\n"
50 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
51 "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
52 "Language-Team: LANGUAGE <LL@li.org>\n"
54 msgid "Report bugs to <bug-gnu-utils@gnu.org>.\n"
61 "internationalized messages should not contain the `\\%c' escape sequence"
64 -#: src/message.c:1115
65 +#: src/message.c:1268 src/message.c:1586
67 msgid "cannot create output file \"%s\""
70 -#: src/message.c:1122
71 +#: src/message.c:1275 src/message.c:1591
73 msgid "standard output"
76 -#: src/message.c:1182
77 +#: src/message.c:1335 src/message.c:1633
79 msgid "error while writing \"%s\" file"
81 diff -urN --exclude Makefile.in --exclude ltconfig --exclude ltmain.sh --exclude configure --exclude build --exclude CVS --exclude config.* --exclude genpatch --exclude .cvsignore --exclude aclocal.m4 --exclude *.po --exclude *.gmo --exclude gettext-0.10.35-hacks.patch gettext.initial/src/Makefile.am gettext.hacked/src/Makefile.am
82 --- gettext.initial/src/Makefile.am Mon Feb 22 13:40:48 1999
83 +++ gettext.hacked/src/Makefile.am Mon Feb 22 18:43:39 1999
86 AUTOMAKE_OPTIONS = 1.2 gnits
88 -bin_PROGRAMS = gettext msgcmp msgfmt msgmerge msgunfmt xgettext msgcomm
89 +bin_PROGRAMS = gettext msgcmp msgfmt msgmerge msgunfmt xgettext msgcomm msghack
91 noinst_HEADERS = domain.h message.h po-gram.h po-hash.h po-lex.h po.h \
92 str-list.h xget-lex.h po-gram.gen.h po-hash.gen.h dir-list.h
94 po.c str-list.c xget-lex.c xgettext.c dir-list.c
95 msgcomm_SOURCES = msgcomm.c message.c po-gram.gen.c po-hash.gen.c po-lex.c \
96 open-po.c po.c str-list.c dir-list.c
98 +msghack_SOURCES = msghack.c open-po.c dir-list.c message.c str-list.c \
99 +po-gram.gen.c po-hash.gen.c po-lex.c po.c
100 MAINTAINERCLEANFILES = po-gram.gen.c po-gram.gen.h po-hash.gen.c po-hash.gen.h
102 # Some rules for yacc handling.
103 diff -urN --exclude Makefile.in --exclude ltconfig --exclude ltmain.sh --exclude configure --exclude build --exclude CVS --exclude config.* --exclude genpatch --exclude .cvsignore --exclude aclocal.m4 --exclude *.po --exclude *.gmo --exclude gettext-0.10.35-hacks.patch gettext.initial/src/message.c gettext.hacked/src/message.c
104 --- gettext.initial/src/message.c Mon Feb 22 13:40:48 1999
105 +++ gettext.hacked/src/message.c Mon Apr 19 05:21:23 1999
107 static void message_print PARAMS ((const message_ty *__mp, FILE *__fp,
108 const char *__domain, int blank_line,
110 +static void master_message_print PARAMS ((const message_ty *__mp,
113 static void message_print_obsolete PARAMS ((const message_ty *__mp, FILE *__fp,
114 const char *__domain,
116 @@ -990,6 +993,156 @@
120 +master_message_print (mp, fp, blank_line)
121 + const message_ty *mp;
127 + /* Separate messages with a blank line. Uniforum doesn't like blank
128 + lines, so use an empty comment (unless there already is one). */
129 + if (blank_line && (!uniforum
130 + || mp->comment == NULL
131 + || mp->comment->nitems == 0
132 + || mp->comment->item[0][0] != '\0'))
133 + print_blank_line (fp);
135 + if (mp->comment != NULL)
136 + for (j = 0; j < mp->comment->nitems; ++j) {
137 + const unsigned char *s = mp->comment->item[j];
139 + const unsigned char *e;
141 + /* FIXME This is the wrong locale. While
142 + message_list_print set the "C" locale for LC_CTYPE,
143 + the need to use the correct locale for the file's
145 + if (*s != '\0' && !isspace (*s))
147 + e = strchr (s, '\n');
152 + fwrite (s, 1, e - s, fp);
156 + } while (s != NULL);
159 + if (mp->comment_dot != NULL)
160 + for (j = 0; j < mp->comment_dot->nitems; ++j) {
161 + const unsigned char *s = mp->comment_dot->item[j];
164 + /* FIXME This is the wrong locale. While
165 + message_list_print set the "C" locale for LC_CTYPE, the
166 + need to use the correct locale for the file's contents. */
167 + if (*s && !isspace (*s))
174 + /* Print the file position comments for every domain. This will
175 + help a human who is trying to navigate the sources. There is no
176 + problem of getting repeat positions, because duplicates are
178 + if (mp->filepos_count != 0) {
180 + for (j = 0; j < mp->filepos_count; ++j) {
181 + lex_pos_ty *pp = &mp->filepos[j];
182 + char *cp = pp->file_name;
183 + while (cp[0] == '.' && cp[1] == '/')
185 + /* There are two Sun formats to choose from: SunOS and
186 + Solaris. Use the Solaris form here. */
187 + fprintf (fp, "# File: %s, line: %ld\n",
188 + cp, (long) pp->line_number);
194 + for (j = 0; j < mp->filepos_count; ++j) {
200 + pp = &mp->filepos[j];
201 + cp = pp->file_name;
202 + while (cp[0] == '.' && cp[1] == '/')
204 + sprintf (buffer, "%ld", (long) pp->line_number);
205 + len = strlen (cp) + strlen (buffer) + 2;
206 + if (column > 2 && column + len >= page_width)
208 + fputs ("\n#:", fp);
211 + fprintf (fp, " %s:%s", cp, buffer);
218 + /* Print flag information in special comment. */
219 + if (mp->is_fuzzy || significant_c_format_p (mp->is_c_format) || mp->do_wrap == no) {
220 + int first_flag = 1;
225 + /* We don't print the fuzzy flag if the msgstr is empty. This
226 + might be introduced by the user but we want to normalize the
228 + if (mp->is_fuzzy) {
229 + fputs (" fuzzy", fp);
233 + if (significant_c_format_p (mp->is_c_format)) {
237 + fputs (make_c_format_description_string (mp->is_c_format, 0),
242 + if (mp->do_wrap == no) {
246 + fputs (make_c_width_description_string (mp->do_wrap), fp);
253 + /* Print each of the message components. Wrap them nicely so they
254 + are as readable as possible. If there is no recorded msgstr for
255 + this domain, emit an empty string. */
256 + wrap (fp, NULL, "msgid", mp->msgid, mp->do_wrap);
257 + for (j = 0; j < mp->variant_count; ++j) {
260 + msgstr = malloc(strlen(mp->variant[j].domain) + 10);
261 + sprintf(msgstr, "msgstr(%s)", mp->variant[j].domain);
263 + wrap (fp, NULL, msgstr, mp->variant[j].msgstr, mp->do_wrap);
270 message_print_obsolete (mp, fp, domain, blank_line)
271 const message_ty *mp;
273 @@ -1402,3 +1555,83 @@
280 + * HACKS... This prints a mesage list, but it uses the
281 + * msgstr(somain) syntax instead
284 +master_list_print (mlp, filename)
285 + message_list_ty *mlp;
286 + const char *filename;
291 +#ifdef HAVE_SETLOCALE
295 + /* We will not write anything if we have no message or only the
297 + if (mlp->nitems == 0 || (mlp->nitems == 1 && *mlp->item[0]->msgid == '\0'))
300 + /* Open the output file. */
301 + if (filename != NULL && strcmp (filename, "-") != 0
302 + && strcmp (filename, "/dev/stdout") != 0) {
303 + fp = fopen (filename, "w");
305 + error (EXIT_FAILURE, errno, _("cannot create output file \"%s\""),
309 + /* xgettext:no-c-format */
310 + filename = _("standard output");
313 +#ifdef HAVE_SETLOCALE
314 + /* FIXME This is the wrong locale. The program is currently set for
315 + the user's native language locale, for the error messages. This
316 + code sets it to the "C" locale, but that isn't right either. The
317 + need is to use the correct locale for the file's contents. */
318 + old_locale = setlocale (LC_CTYPE, "C");
320 + old_locale = xstrdup (old_locale);
323 + /* Write out each of the messages for this domain. */
324 + for (j = 0; j < mlp->nitems; ++j)
325 + if (mlp->item[j]->obsolete == 0) {
326 + master_message_print (mlp->item[j], fp, blank_line);
330 +#if 0 /* screw the obsoletes */
331 + /* Write out each of the obsolete messages for this domain. */
332 + for (j = 0; j < mlp->nitems; ++j)
333 + if (mlp->item[j]->obsolete != 0) {
334 + message_print_obsolete (mlp->item[j], fp, dl->item[k], blank_line);
339 + /* Restore the old locale. Do this before emitting error messages,
340 + so that the correct locale is used for the error. (Ideally,
341 + error should ensure this before calling gettext for the format
343 +#ifdef HAVE_SETLOCALE
345 + setlocale (LC_CTYPE, old_locale);
350 + /* Make sure nothing went wrong. */
352 + error (EXIT_FAILURE, errno, _("error while writing \"%s\" file"),
357 diff -urN --exclude Makefile.in --exclude ltconfig --exclude ltmain.sh --exclude configure --exclude build --exclude CVS --exclude config.* --exclude genpatch --exclude .cvsignore --exclude aclocal.m4 --exclude *.po --exclude *.gmo --exclude gettext-0.10.35-hacks.patch gettext.initial/src/message.h gettext.hacked/src/message.h
358 --- gettext.initial/src/message.h Mon Feb 22 13:40:48 1999
359 +++ gettext.hacked/src/message.h Mon Apr 19 05:21:23 1999
361 int possible_c_format_p PARAMS ((enum is_c_format));
362 void message_page_width_set PARAMS ((size_t width));
364 +/* Hacks go at the end */
365 +void master_list_print PARAMS ((message_list_ty *__mlp, const char *__filename));
367 #endif /* message.h */
368 diff -urN --exclude Makefile.in --exclude ltconfig --exclude ltmain.sh --exclude configure --exclude build --exclude CVS --exclude config.* --exclude genpatch --exclude .cvsignore --exclude aclocal.m4 --exclude *.po --exclude *.gmo --exclude gettext-0.10.35-hacks.patch gettext.initial/src/msghack.c gettext.hacked/src/msghack.c
369 --- gettext.initial/src/msghack.c Wed Dec 31 19:00:00 1969
370 +++ gettext.hacked/src/msghack.c Sun Feb 27 13:30:00 2000
372 +/* GNU gettext - internationalization aids
373 + Copyright (C) 1995, 1996, 1997, 1998, 1999 Free Software Foundation, Inc.
374 + This file was written by Cristian Gafton <gafton@redhat.com>
376 + This program is free software; you can redistribute it and/or modify
377 + it under the terms of the GNU General Public License as published by
378 + the Free Software Foundation; either version 2, or (at your option)
381 + This program is distributed in the hope that it will be useful,
382 + but WITHOUT ANY WARRANTY; without even the implied warranty of
383 + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
384 + GNU General Public License for more details.
386 + You should have received a copy of the GNU General Public License
387 + along with this program; if not, write to the Free Software Foundation,
388 + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
390 +#ifdef HAVE_CONFIG_H
391 +# include <config.h>
399 +# include <stdlib.h>
403 +# include <string.h>
405 +# include <strings.h>
409 +# include <locale.h>
415 +#include "dir-list.h"
417 +#include "message.h"
419 +#include <libintl.h>
422 +#define _(str) gettext (str)
425 +/* This structure defines a derived class of the po_ty class. (See
426 + po.h for an explanation.) */
427 +typedef struct merge_class_ty merge_class_ty;
428 +struct merge_class_ty
430 + /* inherited instance variables, etc */
433 + /* Name of domain we are currently examining. */
436 + /* List of domains already appeared in the current file. */
437 + string_list_ty *domain_list;
439 + /* List of messages already appeared in the current file. */
440 + message_list_ty *mlp;
442 + /* Accumulate comments for next message directive */
443 + string_list_ty *comment;
444 + string_list_ty *comment_dot;
446 + /* Flags transported in special comments. */
448 + enum is_c_format is_c_format;
449 + enum is_c_format do_wrap;
451 + /* Accumulate filepos comments for the next message directive. */
452 + size_t filepos_count;
453 + lex_pos_ty *filepos;
457 +/* String containing name the program is called with. */
458 +const char *program_name;
460 +/* Verbosity level. */
461 +static int verbosity_level;
463 +/* If nonzero, remember comments for file name and line number for each
464 + msgid, if present in the reference input. Defaults to true. */
465 +static int line_comment = 1;
467 +/* Force output of PO file even if empty. */
468 +static int force_po;
470 +/* should we merge in the fuzzy messages ? */
471 +static int fuzzy = 0;
473 +/* Do we want to generate useless merges? */
474 +static int useless = 0;
476 +/* Possible split operations */
477 +#define SPLIT_MSGID 1
478 +#define SPLIT_MSGSTR 2
479 +static int split_flag = 0;
481 +/* Possible explode operations */
482 +#define EXPLODE_MSGID 4
483 +#define EXPLODE_MSGSTR 8
484 +static int explode_flag = 0;
487 +#define SORT_BY_FILEPOS 1
488 +#define SORT_BY_MSGID 2
489 +static int sort_order = 0;
492 +static int comments = 0;
494 +/* Prototypes for local functions. */
495 +static void usage PARAMS ((int __status));
496 +static void error_print PARAMS ((void));
497 +static void merge_constructor PARAMS ((po_ty *__that));
498 +static void merge_destructor PARAMS ((po_ty *__that));
499 +static void merge_directive_domain PARAMS ((po_ty *__that, char *__name));
500 +static void merge_directive_message PARAMS ((po_ty *__that, char *__msgid,
501 + lex_pos_ty *__msgid_pos,
502 + char *__msgstr, lex_pos_ty *__msgstr_pos));
503 +static void merge_parse_brief PARAMS ((po_ty *__that));
504 +static void merge_parse_debrief PARAMS ((po_ty *__that));
505 +static void merge_comment PARAMS ((po_ty *__that, const char *__s));
506 +static void merge_comment_dot PARAMS ((po_ty *__that, const char *__s));
507 +static void merge_comment_special PARAMS ((po_ty *__that, const char *__s));
508 +static void merge_comment_filepos PARAMS ((po_ty *__that, const char *__name,
510 +static message_list_ty *grammar PARAMS ((const char *__filename));
511 +static message_list_ty *append PARAMS ((const char *__fn1, const char *__fn2, int diff_only));
512 +static message_list_ty *merge PARAMS ((const char *__fn1, const char *__fn2));
513 +static message_list_ty *invert PARAMS ((const char *__fn));
514 +static message_list_ty *missing PARAMS ((const char *__fn));
515 +static message_list_ty *un_duplicate PARAMS ((message_list_ty *dup_list));
516 +static message_list_ty *empty PARAMS ((const char *__fn));
517 +static message_list_ty *dummy PARAMS ((const char *__fn));
518 +static message_list_ty *split PARAMS ((const char *__fn, int __flag));
519 +static message_list_ty *explode PARAMS ((const char *__fn, int __flag));
520 +static message_list_ty *master PARAMS ((message_list_ty **prev, const char *__fn,
521 + const char *__master_id));
522 +static message_ty *message_join PARAMS ((message_ty *def, message_ty *ref));
523 +static struct message_ty *new_header PARAMS((void));
525 +/* What kind of actions we can make */
526 +#define ACTION_DO_SPLIT 1
527 +#define ACTION_DO_INVERT 2
528 +#define ACTION_DO_MERGE 3
529 +#define ACTION_DO_EMPTY 4
530 +#define ACTION_DO_EXPLODE 5
531 +#define ACTION_DO_MASTER 6
532 +#define ACTION_DO_SORT 7
533 +#define ACTION_DO_APPEND 8
534 +#define ACTION_DO_UNDUP 9
535 +#define ACTION_DO_MISSING 10
536 +#define ACTION_DO_DUMMY 11
537 +#define ACTION_DO_DIFF 12
539 +int main (argc, argv)
546 + message_list_ty *result;
548 + /* Long options. */
549 + const struct option long_options[] =
551 + /* command pairs */
552 + { "split-id", no_argument, &split_flag, SPLIT_MSGID },
553 + { "split-str", no_argument, &split_flag, SPLIT_MSGSTR },
555 + { "explode-id", required_argument, &explode_flag, EXPLODE_MSGID },
556 + { "explode-str", required_argument, &explode_flag, EXPLODE_MSGSTR },
558 + { "sort-by-file", no_argument, &sort_order, SORT_BY_FILEPOS },
559 + { "sort-by-id", no_argument, &sort_order, SORT_BY_MSGID },
562 + { "fuzzy", no_argument, &fuzzy, 1 },
563 + { "force-po", no_argument, &force_po, 1 },
564 + { "width", required_argument, NULL, 'w', },
565 + { "output-file", required_argument, NULL, 'o' },
566 + { "useless", no_argument, &useless, 1 },
571 + /* switch the msgid and the msgstr strings in a PO file */
572 + { "invert", no_argument, &do_action, ACTION_DO_INVERT },
574 + /* fill the msgstr with the contents of msgid */
575 + { "dummy", no_argument, &do_action, ACTION_DO_DUMMY },
577 + /* merge two files based on commin msgid. The msgid is stored as a comment */
578 + { "merge", no_argument, &do_action, ACTION_DO_MERGE },
580 + /* strip out the msgstr creating a POT form a PO file */
581 + { "empty", no_argument, &do_action, ACTION_DO_EMPTY },
583 + /* combine sevaral PO files into a "master" catalog */
584 + { "master", no_argument, &do_action, ACTION_DO_MASTER },
586 + /* append entries from ref POT that do not exist in file PO */
587 + { "append", no_argument, &do_action, ACTION_DO_APPEND },
589 + /* show only stuff from ref POT that does not exist in file PO */
590 + { "diff", no_argument, &do_action, ACTION_DO_DIFF },
592 + /* ommit comments for the 'append' and 'diff' */
593 + { "comments", no_argument, &comments, 1 },
595 + /* remove duplicates */
596 + { "unduplicate", no_argument, &do_action, ACTION_DO_UNDUP },
598 + /* output strings that need translation (fuzzies and untranslated */
599 + { "missing", no_argument, &do_action, ACTION_DO_MISSING },
601 + /* output strings that need translation (fuzzies and untranslated */
602 + { "missing", no_argument, &do_action, ACTION_DO_MISSING },
605 + { "help", no_argument, NULL, 'h' },
606 + { "version", no_argument, NULL, 'V' },
608 + { NULL, 0, NULL, 0 }
612 + /* Set program name for messages. */
613 + program_name = argv[0];
614 + verbosity_level = 0;
615 + error_print_progname = error_print;
616 + gram_max_allowed_errors = INT_MAX;
618 +#ifdef HAVE_SETLOCALE
619 + /* Set locale via LC_ALL. */
620 + setlocale (LC_ALL, "");
623 + /* Set the text message domain. */
624 + bindtextdomain (PACKAGE, LOCALEDIR);
625 + textdomain (PACKAGE);
627 + /* Set default values for variables. */
628 + output_file = NULL;
631 + = getopt_long (argc, argv, "ho:Vw:v", long_options, NULL))
634 + case '\0': /* Long option. */
638 + /* Help is requested. */
639 + usage (EXIT_SUCCESS);
643 + output_file = optarg;
651 + /* Version information is requested. */
652 + printf ("%s (GNU %s) %s\n", basename (program_name), PACKAGE, VERSION);
653 + /* xgettext: no-wrap */
654 + printf (_("Copyright (C) %s Free Software Foundation, Inc.\n\
655 +This is free software; see the source for copying conditions. There is NO\n\
656 +warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\
657 +"), "1995, 1996, 1997, 1998");
658 + printf (_("Written by %s.\n"), "Cristian Gafton");
659 + exit (EXIT_SUCCESS);
666 + value = strtol (optarg, &endp, 10);
667 + if (endp != optarg)
668 + message_page_width_set (value);
673 + usage (EXIT_FAILURE);
677 + /* Test whether we have an .po file name as argument. */
678 + if (optind >= argc) {
679 + error (EXIT_SUCCESS, 0, _("no input files given"));
680 + usage (EXIT_FAILURE);
683 + /* transform one of the pair command into a real action */
684 + if (do_action == 0 && split_flag > 0)
685 + do_action = ACTION_DO_SPLIT;
686 + if (do_action == 0 && explode_flag > 0)
687 + do_action = ACTION_DO_EXPLODE;
688 + if (do_action == 0 && sort_order != 0)
689 + do_action = ACTION_DO_SORT;
691 + /* okay, we have our file in argv[optind]*/
692 + /* what should we do */
693 + switch (do_action) {
694 + case ACTION_DO_INVERT:
695 + /* we are asked to invert the msgid and msgstr strings in a .po file */
696 + result = invert (argv[optind]);
698 + case ACTION_DO_EMPTY:
699 + /* we are asked to delete the msgstr text in a .po file */
700 + result = empty (argv[optind]);
702 + case ACTION_DO_DUMMY:
703 + /* dummy out a POT file in a PO file (msgstr = msgid) */
704 + result = dummy (argv[optind]);
706 + case ACTION_DO_SPLIT:
707 + /* we are asked to split the file into corresponding meta po files */
708 + result = split(argv[optind], split_flag);
709 + /* Whatever we are asked to split out */
711 + case ACTION_DO_EXPLODE:
712 + /* we are asked to generate a single meta entry for each xref */
713 + result = explode(argv[optind], explode_flag);
715 + case ACTION_DO_MERGE:
716 + /* we gave to merge (id1,str1) and (id2,str2) into (str1,str2) */
717 + if (optind + 2 != argc) {
718 + error (EXIT_SUCCESS, 0, _("exactly 2 input files required for merge"));
719 + usage (EXIT_FAILURE);
721 + result = merge (argv[optind], argv[optind+1]);
723 + case ACTION_DO_DIFF:
724 + case ACTION_DO_APPEND:
725 + /* append all (id2,str2) entries from second file to the first one
726 + * provided that a id2 msgid is not already present there */
727 + if (optind + 2 != argc) {
728 + error (EXIT_SUCCESS, 0, _("exactly 2 input files required for append"));
729 + usage (EXIT_FAILURE);
731 + result = append (argv[optind], argv[optind+1], do_action == ACTION_DO_DIFF);
733 + case ACTION_DO_UNDUP:
734 + /* read in the message catalog and try to colapse
735 + the duplicate messageids together */
736 + /* Read in the file */
737 + result = grammar (argv[optind]);
738 + result = un_duplicate(result);
740 + case ACTION_DO_MASTER:
741 + /* This is a little bit funkier:
742 + * Suppose in A.po we have:
745 + * And in B.po we have:
748 + * then the result will look like:
753 + result = NULL; /* Start from scratch */
754 + for (opt = optind ; opt < argc ; opt++) {
755 + char *file_name, *master_id;
757 + /* get the file name and the master id */
758 + file_name = strdup(argv[opt]);
759 + master_id = strdup(basename(argv[opt]));
760 + tmp = rindex(master_id, '.');
762 + error (EXIT_SUCCESS, 0,
763 + _("Message catalog %s does not have a valid name"), argv[opt]);
764 + usage (EXIT_FAILURE);
767 + result = master(&result, file_name, master_id);
769 + master_list_print(result, output_file);
770 + return EXIT_SUCCESS;
772 + case ACTION_DO_SORT:
773 + /* we'll just read in the file and let the sort
774 + * statements later deal with it */
775 + result = grammar (argv[optind]);
777 + case ACTION_DO_MISSING:
778 + /* generate a new po file of only the missing and non-translated strings */
779 + result = missing (argv[optind]);
782 + error (EXIT_SUCCESS, 0, _("Unknown Action"));
783 + exit(EXIT_FAILURE);
786 + /* Sort the results. */
787 + switch (sort_order) {
788 + case SORT_BY_FILEPOS:
789 + message_list_sort_by_filepos (result);
791 + case SORT_BY_MSGID:
792 + message_list_sort_by_msgid (result);
796 + /* Write the merged message list out. */
797 + message_list_print (result, output_file, force_po, 0);
799 + exit (EXIT_SUCCESS);
803 +/* Display usage information and exit. */
808 + if (status != EXIT_SUCCESS)
809 + fprintf (stderr, _("Try `%s --help' for more information.\n"),
812 + /* xgettext: no-wrap */
814 +Usage: %s [OPTION] file.po [ref.po]\n\
815 +Mandatory arguments to long options are mandatory for short options too.\n\
816 + -h, --help display this help and exit\n\
817 + --invert invert a po file by switching msgid and msgstr\n\
818 + -o, --output-file=FILE result will be written to FILE\n\
819 + -v, --verbose increase verbosity level\n\
820 + -V, --version output version information and exit\n\
821 + -w, --width=NUMBER set output page width\n\
822 + --sort-by-file sort by file in which the msgs appear\n\
823 + --sort-by-id sort by message ids\n\
824 + --split-id split msgid from message catalg into meta catalog\n\
825 + --split-str split msgstr from message catalg into meta catalog\n\
826 + --merge merge file.po and ref.po based on the common msgid\n\
827 + + --useless also generate entries for unmatched pairs.\n\
828 + --master join any number of files in a master-formatted catalog\n\
829 + + --fuzzy use the fuzzy entries when merging in PO files.\n\
830 + --empty empty the contents of the .po file, creating a .pot\n\
831 + --dummy create a .po file from a .pot by doing msgstr = msgid\n\
832 + --append append entries from ref.po that don't exist in file.po\n\
833 + --diff show what entries from ref.po don't exist in file.po\n\
834 + + --comments add comments from ref.po for existing entries. in file.po.\n\
835 + --explode-id generate a single meta msgid entry for each xref in file.po\n\
836 + --explode-str generate a single meta msgstr entry for each xref in file.po\n\
837 + --unduplicate colapse together duplicate message ids. (not working currently)\n\
838 + --missing output only the fuzzy and empty message strings\n\
840 +This program can be used to alter .po files in ways no sane mind would think about.\n\
841 +Report problems to <gafton@redhat.com>\n\
848 +/* The address of this function will be assigned to the hook in the
849 + error functions. */
850 +static void error_print ()
852 + /* We don't want the program name to be printed in messages. Emacs'
853 + compile.el does not like this. */
855 + /* FIXME Why must this program toady to Emacs? Why can't compile.el
856 + be enhanced to cope with a leading program name? --PMiller */
861 +merge_constructor (that)
864 + merge_class_ty *this = (merge_class_ty *) that;
866 + this->mlp = message_list_alloc ();
867 + this->domain = MESSAGE_DOMAIN_DEFAULT;
868 + this->domain_list = string_list_alloc ();
869 + this->comment = NULL;
870 + this->comment_dot = NULL;
871 + this->filepos_count = 0;
872 + this->filepos = NULL;
873 + this->is_fuzzy = 0;
874 + this->is_c_format = undecided;
875 + this->do_wrap = undecided;
880 +merge_destructor (that)
883 + merge_class_ty *this = (merge_class_ty *) that;
886 + string_list_free (this->domain_list);
887 + /* Do not free this->mlp. */
888 + if (this->comment != NULL)
889 + string_list_free (this->comment);
890 + if (this->comment_dot != NULL)
891 + string_list_free (this->comment_dot);
892 + for (j = 0; j < this->filepos_count; ++j)
893 + free (this->filepos[j].file_name);
894 + if (this->filepos != NULL)
895 + free (this->filepos);
900 +merge_directive_domain (that, name)
906 + merge_class_ty *this = (merge_class_ty *) that;
907 + /* Override current domain name. Don't free memory. */
908 + this->domain = name;
910 + /* If there are accumulated comments, throw them away, they are
911 + probably part of the file header, or about the domain directive,
912 + and will be unrelated to the next message. */
913 + if (this->comment != NULL)
915 + string_list_free (this->comment);
916 + this->comment = NULL;
918 + if (this->comment_dot != NULL)
920 + string_list_free (this->comment_dot);
921 + this->comment_dot = NULL;
923 + for (j = 0; j < this->filepos_count; ++j)
924 + free (this->filepos[j].file_name);
925 + if (this->filepos != NULL)
926 + free (this->filepos);
927 + this->filepos_count = 0;
928 + this->filepos = NULL;
933 +merge_directive_message (that, msgid, msgid_pos, msgstr, msgstr_pos)
936 + lex_pos_ty *msgid_pos;
938 + lex_pos_ty *msgstr_pos;
940 + merge_class_ty *this = (merge_class_ty *) that;
942 + message_variant_ty *mvp;
945 + /* Remember the domain names for later. */
946 + string_list_append_unique (this->domain_list, this->domain);
948 + /* See if this message ID has been seen before. */
949 + mp = message_list_search (this->mlp, msgid);
954 + mp = message_alloc (msgid);
955 + message_list_append (this->mlp, mp);
958 + /* Add the accumulated comments to the message. Clear the
959 + accumulation in preparation for the next message. */
960 + if (this->comment != NULL)
962 + for (j = 0; j < this->comment->nitems; ++j)
963 + message_comment_append (mp, this->comment->item[j]);
964 + string_list_free (this->comment);
965 + this->comment = NULL;
967 + if (this->comment_dot != NULL)
969 + for (j = 0; j < this->comment_dot->nitems; ++j)
970 + message_comment_dot_append (mp, this->comment_dot->item[j]);
971 + string_list_free (this->comment_dot);
972 + this->comment_dot = NULL;
974 + for (j = 0; j < this->filepos_count; ++j)
978 + pp = &this->filepos[j];
979 + message_comment_filepos (mp, pp->file_name, pp->line_number);
980 + free (pp->file_name);
982 + mp->is_fuzzy = this->is_fuzzy;
983 + mp->is_c_format = this->is_c_format;
984 + mp->do_wrap = this->do_wrap;
986 + if (this->filepos != NULL)
987 + free (this->filepos);
988 + this->filepos_count = 0;
989 + this->filepos = NULL;
990 + this->is_fuzzy = 0;
991 + this->is_c_format = undecided;
992 + this->do_wrap = undecided;
994 + /* See if this domain has been seen for this message ID. */
995 + mvp = message_variant_search (mp, this->domain);
998 + gram_error_at_line (msgid_pos, _("duplicate message definition"));
999 + gram_error_at_line (&mvp->pos, _("\
1000 +...this is the location of the first definition"));
1004 + message_variant_append (mp, this->domain, msgstr, msgstr_pos);
1009 +merge_parse_brief (that)
1012 + po_lex_pass_comments (1);
1017 +merge_parse_debrief (that)
1020 + merge_class_ty *this = (merge_class_ty *) that;
1021 + message_list_ty *mlp = this->mlp;
1024 + /* For each domain in the used-domain-list, make sure each message
1025 + defines a msgstr in that domain. */
1026 + for (j = 0; j < this->domain_list->nitems; ++j)
1028 + const char *domain_name;
1031 + domain_name = this->domain_list->item[j];
1032 + for (k = 0; k < mlp->nitems; ++k)
1034 + const message_ty *mp;
1037 + mp = mlp->item[k];
1038 + for (m = 0; m < mp->variant_count; ++m)
1040 + message_variant_ty *mvp;
1042 + mvp = &mp->variant[m];
1043 + if (strcmp (domain_name, mvp->domain) == 0)
1046 + if (m >= mp->variant_count)
1047 + gram_error_at_line (&mp->variant[0].pos, _("\
1048 +this message has no definition in the \"%s\" domain"), domain_name);
1055 +merge_comment (that, s)
1059 + merge_class_ty *this = (merge_class_ty *) that;
1061 + if (this->comment == NULL)
1062 + this->comment = string_list_alloc ();
1063 + string_list_append (this->comment, s);
1068 +merge_comment_dot (that, s)
1072 + merge_class_ty *this = (merge_class_ty *) that;
1074 + if (this->comment_dot == NULL)
1075 + this->comment_dot = string_list_alloc ();
1076 + string_list_append (this->comment_dot, s);
1081 +merge_comment_special (that, s)
1085 + merge_class_ty *this = (merge_class_ty *) that;
1087 + if (strstr (s, "fuzzy") != NULL)
1088 + this->is_fuzzy = 1;
1090 + this->is_c_format = parse_c_format_description_string (s);
1091 + this->do_wrap = parse_c_width_description_string (s);
1096 +merge_comment_filepos (that, name, line)
1101 + merge_class_ty *this = (merge_class_ty *) that;
1105 + if (!line_comment)
1107 + nbytes = (this->filepos_count + 1) * sizeof (this->filepos[0]);
1108 + this->filepos = xrealloc (this->filepos, nbytes);
1109 + pp = &this->filepos[this->filepos_count++];
1110 + pp->file_name = xstrdup (name);
1111 + pp->line_number = line;
1115 +/* So that the one parser can be used for multiple programs, and also
1116 + use good data hiding and encapsulation practices, an object
1117 + oriented approach has been taken. An object instance is allocated,
1118 + and all actions resulting from the parse will be through
1119 + invokations of method functions of that object. */
1121 +static po_method_ty merge_methods =
1123 + sizeof (merge_class_ty),
1124 + merge_constructor,
1126 + merge_directive_domain,
1127 + merge_directive_message,
1128 + merge_parse_brief,
1129 + merge_parse_debrief,
1131 + merge_comment_dot,
1132 + merge_comment_filepos,
1133 + merge_comment_special
1137 +static message_list_ty *
1139 + const char *filename;
1142 + message_list_ty *mlp;
1144 + pop = po_alloc (&merge_methods);
1145 + po_lex_pass_obsolete_entries (1);
1146 + po_scan (pop, filename);
1147 + mlp = ((merge_class_ty *) pop)->mlp;
1153 +#define DOT_FREQUENCE 10
1156 + * Given two meta files (m,X) and (m,N) generate a po file (N,X)
1157 + * preserving the meta information in special comments
1159 +static message_list_ty *
1161 + const char *fn1; /* definitions */
1162 + const char *fn2; /* references */
1164 + message_list_ty *def;
1165 + message_list_ty *ref;
1166 + message_ty *defmsg;
1168 + size_t merged, fuzzied, missing, obsolete;
1169 + message_list_ty *result;
1171 + /* This is the definitions file, created by a human. */
1172 + def = grammar (fn1);
1174 + /* This is the references file, created by groping the sources with
1175 + * the xgettext program. */
1176 + ref = grammar (fn2);
1178 + result = message_list_alloc ();
1180 + /* Every reference must be matched with its definition. */
1181 + for (j = 0; j < ref->nitems; ++j) {
1182 + message_ty *refmsg;
1184 + /* Because merging can take a while we print something to signal
1185 + * we are not dead. */
1186 + if (verbosity_level >= 1 && j % DOT_FREQUENCE == 0)
1187 + fputc ('.', stderr);
1189 + refmsg = ref->item[j];
1191 + /* See if it is in the other file. */
1192 + defmsg = message_list_search (def, refmsg->msgid);
1194 + /* Merge the reference with the definition: take the #. and
1195 + #: comments from the reference, take the # comments from
1196 + the definition, take the msgstr from the definition. Add
1197 + this merged entry to the output message list. */
1198 + message_ty *mp = message_join (defmsg, refmsg);
1201 + message_list_append (result, mp);
1203 + /* Remember that this message has been used, when we scan
1204 + later to see if anything was omitted. */
1208 + } else if (useless) {
1211 + if (verbosity_level > 1)
1212 + gram_error_at_line (&refmsg->variant[0].pos,
1213 + _("this message is used but not defined in %s"),
1216 + /* Insert the blank record */
1217 + mp = message_copy (refmsg);
1219 + mp->msgid = mp->variant[0].msgstr;
1220 + mp->variant[0].msgstr = "";
1221 + message_list_append (result, mp);
1226 + /* Look for messages in the definition file, which are not present
1227 + in the reference file, indicating messages which defined but not
1228 + used in the program. */
1230 + for (k = 0; k < def->nitems; ++k) {
1231 + defmsg = def->item[k];
1235 + /* Remember the old translation although it is not used anymore.
1236 + But we mark it as obsolete. */
1237 + defmsg->obsolete = 1;
1239 + message_list_append (result, defmsg);
1243 + /* Report some statistics. */
1244 + if (verbosity_level > 0)
1246 + _("%sRead %d old + %d reference, merged %d, fuzzied %d, missing %d, obsolete %d.\n"),
1247 + verbosity_level >= 1 ? "\n" : "",
1248 + def->nitems, ref->nitems, merged, fuzzied, missing, obsolete);
1249 + else if (verbosity_level > 0)
1250 + fputs (_(" done.\n"), stderr);
1252 + /* get rid of the duplicate message ids */
1253 + return un_duplicate(result);
1257 + * Given two meta files f1 and f2 append to f1 the entries from f2 that
1258 + * are not found in f1. First f1 is read in, the for each entry in f2 we
1259 + * try to locate it in f1; if it is not there already we add it.
1261 +static message_list_ty *
1262 +append (fn1, fn2, diff_only)
1263 + const char *fn1; /* base file */
1264 + const char *fn2; /* more stuff found in here */
1265 + int diff_only; /* do we want only the diffs? */
1267 + message_list_ty *ml1;
1268 + message_list_ty *ml2;
1269 + message_list_ty *result;
1274 + /* This is the definitions file, created by a human. */
1275 + ml1 = grammar (fn1);
1276 + initial = ml1->nitems;
1278 + /* This is the references file, created by groping the sources with
1279 + * the xgettext program. */
1280 + ml2 = grammar (fn2);
1282 + result = message_list_alloc();
1284 + /* Every reference must be matched with its definition. */
1285 + for (j = 0; j < ml2->nitems; ++j) {
1286 + message_ty *oldmsg;
1287 + message_ty *newmsg;
1290 + /* Because merging can take a while we print something to signal
1291 + * we are not dead. */
1292 + if (verbosity_level >= 1 && j % DOT_FREQUENCE == 0)
1293 + fputc ('.', stderr);
1295 + /* this is the message we want to add */
1296 + newmsg = ml2->item[j];
1298 + /* See if it is in the other file. */
1299 + oldmsg = message_list_search (ml1, newmsg->msgid);
1300 + if (oldmsg == NULL) { /* not found, stick it in */
1301 + message_list_append (result, newmsg);
1307 + /* else, if it is found, add the coments from it if we want them */
1308 + if (comments != 0) {
1309 + if (newmsg->comment)
1310 + for (i = 0; i < newmsg->comment->nitems; ++i)
1311 + message_comment_append (oldmsg, newmsg->comment->item[i]);
1313 + if (newmsg->comment_dot)
1314 + for (i = 0; i < newmsg->comment_dot->nitems; ++i)
1315 + message_comment_dot_append (oldmsg, newmsg->comment_dot->item[i]);
1317 + /* file position comments */
1318 + for (i = 0; i < newmsg->filepos_count; ++i) {
1319 + lex_pos_ty *pp = &newmsg->filepos[i];
1320 + message_comment_filepos (oldmsg, pp->file_name, pp->line_number);
1326 + /* Report some statistics. */
1327 + if (verbosity_level > 0)
1329 + _("%sRead %d file1 + %d file2, added %d\n"),
1330 + verbosity_level >= 1 ? "\n" : "",
1331 + initial, ml2->nitems, added);
1332 + else if (verbosity_level > 0)
1333 + fputs (_(" done.\n"), stderr);
1335 + /* do we want only the diffs? */
1340 + /* append the result to ml1 */
1341 + for (j = 0; j < result->nitems; ++j)
1342 + message_list_append(ml1, result->item[j]);
1344 + /* No need to free the result since message_list_alloc copies only the
1345 + references over */
1349 +static message_list_ty *
1350 +master (prev, fn, master_id)
1351 + message_list_ty **prev; /* The result of what we had before */
1352 + const char *fn; /* file name */
1353 + const char *master_id; /* what to put as msgstr(master_id) */
1355 + message_list_ty *list;
1356 + message_list_ty *result;
1359 + /* Read in the file */
1360 + list = grammar (fn);
1362 + if (*prev == NULL)
1363 + *prev = message_list_alloc ();
1365 + result = *prev; /* Work with that */
1367 + /* Every reference must be matched with its definition. */
1368 + for (j = 0; j < list->nitems; ++j) {
1369 + message_ty *crtmsg, *merge_msg;
1371 + /* check for empty message ids == headers */
1372 + if (list->item[j]->msgid[0] == '\0') {
1376 + if ((list->item[j])->is_fuzzy && (fuzzy == 0)) {
1377 + /* we don't want fuzzies */
1381 + crtmsg = message_copy (list->item[j]);
1383 + /* First, search its pair in the result list ... */
1384 + merge_msg = message_list_search (result, crtmsg->msgid);
1386 + /* Now here is something broken: we get only the msgstr
1387 + * from the variant[0] and override its domain with our master_id
1389 + crtmsg->variant_count = 1;
1390 + crtmsg->variant[0].domain = master_id;
1392 + if (merge_msg != NULL) {
1396 + /* Ah! we have to do a nasty merge */
1397 + variants = ++merge_msg->variant_count;
1398 + temp = realloc (merge_msg->variant, variants * sizeof(crtmsg->variant[0]));
1399 + if (temp != NULL) {
1400 + merge_msg->variant = temp;
1402 + error (EXIT_FAILURE, 0, "OUT of memory in %s", __FUNCTION__);
1405 + merge_msg->variant[variants-1] = crtmsg->variant[0];
1406 + /* that should be it */
1408 + /* this is really simple - just add it */
1409 + message_list_append (result, crtmsg);
1412 + /* Remember that this message has been used, when we scan
1413 + later to see if anything was omitted. */
1420 +static message_list_ty *
1422 + const char *fn; /* file name */
1424 + message_list_ty *list;
1426 + size_t inverted = 0;
1427 + message_list_ty *result;
1429 + /* Read in the file */
1430 + list = grammar (fn);
1432 + result = message_list_alloc ();
1434 + /* Every reference must be matched with its definition. */
1435 + for (j = 0; j < list->nitems; ++j) {
1436 + message_ty *crtmsg;
1439 + /* check for empty message ids == headers */
1440 + if (list->item[j]->msgid[0] == '\0') {
1441 + message_list_append (result, list->item[j]);
1445 + crtmsg = message_copy (list->item[j]);
1448 + * Now invert it. For each domain found in the file we create a record
1449 + * containing the inverted pair
1451 + for (k = 0; k < crtmsg->variant_count; k++) {
1455 + mp = message_copy(crtmsg);
1456 + mp->variant_count = 1;
1458 + mp->msgid = crtmsg->variant[k].msgstr;
1459 + mp->variant[0] = crtmsg->variant[k];
1460 + mp->variant[0].msgstr = tmp;
1461 + message_list_append (result, mp);
1465 + /* Remember that this message has been used, when we scan
1466 + later to see if anything was omitted. */
1470 + /* get rid of the duplicate message ids */
1471 + return un_duplicate(result);
1474 +static message_list_ty *
1476 + const char *fn; /* file name */
1478 + message_list_ty *list;
1480 + message_list_ty *result;
1482 + /* Read in the file */
1483 + list = grammar (fn);
1485 + result = message_list_alloc ();
1487 + /* Every reference must be matched with its definition. */
1488 + for (j = 0; j < list->nitems; ++j) {
1491 + /* check for empty message ids == headers */
1492 + if (list->item[j]->msgid[0] == '\0') {
1493 + message_list_append (result, list->item[j]);
1497 + /* Fuzzies go in */
1498 + if (list->item[j]->is_fuzzy) {
1499 + message_list_append (result, list->item[j]);
1503 + /* Check for empty translations */
1504 + for (k = 0; k < list->item[j]->variant_count; k++) {
1505 + if (strlen(list->item[j]->variant[k].msgstr) <= 1) {
1506 + message_list_append (result, list->item[j]);
1511 + /* Remember that this message has been used, when we scan
1512 + later to see if anything was omitted. */
1513 + list->item[j]->used = 1;
1518 +static message_list_ty *
1519 +un_duplicate (dup_list)
1520 + message_list_ty *dup_list; /* list containing duplicates */
1522 + message_list_ty *result;
1525 + result = message_list_alloc ();
1527 + /* First iteration, clear the used flag */
1528 + for (j = 0; j < dup_list->nitems; ++j)
1529 + dup_list->item[j]->used = 0;
1531 + /* This is a cheesy O(n^2) dupe elimination "algorithm"
1532 + * One day I will replace it by a quicksort() followed by
1533 + * a walk through the whole list one more time and that will bring
1534 + * it down to O(n log(n)) */
1535 + for (j = 0; j < dup_list->nitems; ++j) {
1536 + message_ty *crtmsg;
1539 + /* get the current message */
1540 + crtmsg = dup_list->item[j];
1542 + if (crtmsg->used > 0)
1545 + for (k = j + 1; k < dup_list->nitems; ++k) {
1546 + message_ty *newmsg;
1549 + newmsg = dup_list->item[k];
1551 + if (strcmp(crtmsg->msgid, newmsg->msgid) != 0 ||
1555 + if (newmsg->comment)
1556 + for (i = 0; i < newmsg->comment->nitems; ++i)
1557 + message_comment_append (crtmsg, newmsg->comment->item[i]);
1559 + if (newmsg->comment_dot)
1560 + for (i = 0; i < newmsg->comment_dot->nitems; ++i)
1561 + message_comment_dot_append (crtmsg, newmsg->comment_dot->item[i]);
1563 + /* file position comments */
1564 + for (i = 0; i < newmsg->filepos_count; ++i) {
1565 + lex_pos_ty *pp = &newmsg->filepos[i];
1566 + message_comment_filepos (crtmsg, pp->file_name, pp->line_number);
1569 + fprintf(stderr, "%05d : %05d\r", j, k);
1570 + /* Now mark it as used */
1574 + /* Now put the resulting entry on the final list */
1575 + message_list_append (result, crtmsg);
1583 +message_join (def, ref)
1587 + message_ty *result;
1589 + char *meta_comment;
1591 + /* is this the header ? */
1592 + if (ref->msgid[0] == '\0') {
1593 + result = message_copy(ref);
1599 + * We are not processing in any way the variant list at this time.
1600 + * We assume blindly that joining two pairs onn variant[0] will yield
1601 + * the correct result
1604 + /* here it goes: (m,X) join m(m,N) = (N,X) */
1605 + result = message_copy(def);
1606 + /* here we should be looping over all domains */
1607 + result->msgid = ref->variant[0].msgstr;
1610 + /* Trim down on crap translations */
1611 + if (result->variant[0].msgstr == NULL)
1613 + if (strlen(result->variant[0].msgstr) == 0)
1615 + if (strcmp(result->msgid, result->variant[0].msgstr) == 0)
1619 + /* Take the comments from the definition file. There will be none at
1620 + * all in the reference file, as it was generated by xgettext.
1622 + /* we don't do that here because result is already initialized from def
1624 + /*if (def->comment) */
1625 + /* for (j = 0; j < def->comment->nitems; ++j) */
1626 + /* message_comment_append (result, def->comment->item[j]); */
1628 + /* now add the meta information for the common join field */
1629 + j = strlen(ref->msgid) + 10;
1630 + meta_comment = alloca(j);
1631 + if (meta_comment != NULL) {
1632 + snprintf(meta_comment, j-1, "meta=%s", ref->msgid); /* should be safe */
1633 + message_comment_append(result, meta_comment);
1635 + message_comment_append(result, "meta=ERROR!!!");
1636 + message_comment_append(result, ref->msgid);
1639 + /* Take the dot comments from the reference file, as they are
1640 + generated by xgettext. Any in the definition file are old ones
1641 + collected by previous runs of xgettext and msgmerge. */
1642 + if (ref->comment_dot)
1643 + for (j = 0; j < ref->comment_dot->nitems; ++j)
1644 + message_comment_dot_append (result, ref->comment_dot->item[j]);
1646 +/* message_comment_dot_append(result, "this is my test"); */
1647 + /* The flags are mixed in a special way. Some informations come
1648 + from the reference message (such as format/no-format), others
1649 + come from the definition file (fuzzy or not). */
1650 + result->is_fuzzy = def->is_fuzzy;
1651 + result->is_c_format = ref->is_c_format;
1652 + result->do_wrap = ref->do_wrap;
1654 + /* Take the file position comments from the reference file, as they
1655 + are generated by xgettext. Any in the definition file are old ones
1656 + collected by previous runs of xgettext and msgmerge. */
1657 + for (j = 0; j < ref->filepos_count; ++j) {
1658 + lex_pos_ty *pp = &ref->filepos[j];
1659 + message_comment_filepos (result, pp->file_name, pp->line_number);
1662 + /* All done, return the merged message to the caller. */
1666 +static message_list_ty *
1668 + const char *fn; /* file name */
1669 + int flag; /* what should we be splitting out */
1671 + message_list_ty *list;
1673 + message_list_ty *result;
1675 + /* Read in the file */
1676 + list = grammar (fn);
1678 + result = message_list_alloc ();
1680 + /* Every reference must be matched with its definition. */
1681 + for (j = 0; j < list->nitems; ++j) {
1682 + message_ty *crtmsg;
1684 + /* get the current message */
1685 + crtmsg = message_copy (list->item[j]);
1687 + /* search all comments looking for our meta= */
1688 + if (crtmsg->comment) {
1690 + for (k = 0; k < crtmsg->comment->nitems; ++k) {
1693 + tmp = strstr(crtmsg->comment->item[k], "meta=");
1694 + if (tmp != NULL) { /* found it */
1697 + message_variant_ty *mvp = NULL;
1699 + res = message_alloc(xstrdup(tmp+5));
1700 + res->variant_count = 1;
1701 + mvp = malloc(sizeof(struct message_variant_ty));
1702 + if (mvp == NULL) {
1703 + error (EXIT_FAILURE, 0, _("Weird out of memory situation"));
1704 + usage (EXIT_FAILURE);
1706 + *mvp = crtmsg->variant[0];
1707 + res->variant = mvp;
1710 + res->variant[0].msgstr = crtmsg->msgid;
1711 + /* transport over all the dot comments */
1712 + if (crtmsg->comment_dot)
1713 + for (i = 0; i < crtmsg->comment_dot->nitems; ++i)
1714 + message_comment_dot_append(res, crtmsg->comment_dot->item[i]);
1716 + case SPLIT_MSGSTR:
1717 + res->variant[0].msgstr = crtmsg->variant[0].msgstr;
1718 + /* transport over the comments with the exception of
1719 + the dot comments and the meta= one */
1720 + for (i = 0; i < crtmsg->comment->nitems; ++i)
1722 + message_comment_append(res, crtmsg->comment->item[i]);
1725 + error (EXIT_SUCCESS, 0, _("Unknwon split mode"));
1726 + usage (EXIT_FAILURE);
1728 + message_list_append (result, res);
1732 + /* we have no meta comment on this one */
1739 +static message_list_ty *
1741 + const char *fn; /* file name */
1742 + int flag; /* what should we be splitting out */
1744 + message_list_ty *list;
1746 + message_list_ty *result;
1748 + /* Read in the file */
1749 + list = grammar (fn);
1751 + result = message_list_alloc ();
1753 + /* Every reference ... */
1754 + for (j = 0; j < list->nitems; ++j) {
1755 + message_ty *crtmsg;
1758 + /* Get the current message */
1759 + crtmsg = message_copy (list->item[j]);
1761 + /* Every "conformant" cross reference ... */
1762 + for (k = 0; k < crtmsg->filepos_count; ++k) {
1765 + const char *fn, *tn;
1766 + const char *f, *fe;
1770 + message_variant_ty *mvp = NULL;
1772 + pp = &crtmsg->filepos[k];
1773 + fn = pp->file_name;
1774 + ln = pp->line_number;
1784 + tn = "(Description)";
1791 + /* ... weird tags we do not want */
1795 + /* Find the text after the name-version-release */
1796 + if ((f = strrchr(fn, '-')) == NULL ||
1797 + (fe = strchr(f, '.')) == NULL) {
1798 + fprintf(stderr, _("skipping malformed xref \"%s\"\n"), fn);
1801 + fe = fn + strlen(fn) - sizeof(".src.rpm") + 1;
1803 + /* ... src.rpm's we do not want */
1804 + if ( !strcmp(fe, ".src.rpm") )
1807 + /* Position at end of name */
1808 + fe = strrchr(fn, '-') - 1;
1809 + while (fe > fn && *fe != '-')
1812 + /* Construct meta tag */
1813 + strncpy(buf, fn, (fe-fn) );
1814 + buf[fe-fn] = '\0';
1815 + strncat(buf, tn, (sizeof(buf) - strlen(buf)) );
1817 + res = message_alloc(xstrdup(buf));
1818 + res->variant_count = 1;
1819 + mvp = malloc(sizeof(struct message_variant_ty));
1820 + if (mvp == NULL) {
1821 + error (EXIT_FAILURE, 0, _("Weird out of memory situation"));
1822 + usage (EXIT_FAILURE);
1824 + *mvp = crtmsg->variant[0];
1825 + res->variant = mvp;
1827 + case EXPLODE_MSGID:
1828 + res->variant[0].msgstr = crtmsg->msgid;
1829 + /* transport over all the dot comments */
1830 + if (crtmsg->comment_dot)
1831 + for (i = 0; i < crtmsg->comment_dot->nitems; ++i)
1832 + message_comment_dot_append(res, crtmsg->comment_dot->item[i]);
1834 + case EXPLODE_MSGSTR:
1835 + res->variant[0].msgstr = crtmsg->variant[0].msgstr;
1837 + /* transport over the comments with the exception of
1838 + the dot comments */
1839 + for (i = 0; i < crtmsg->comment->nitems; ++i)
1840 + message_comment_append(res, crtmsg->comment->item[i]);
1844 + error (EXIT_SUCCESS, 0, _("Unknwon explode mode"));
1845 + usage (EXIT_FAILURE);
1847 + message_list_append (result, res);
1853 +static message_list_ty *
1855 + const char *fn; /* file name */
1857 + message_list_ty *list;
1859 + int had_header = 0;
1860 + message_list_ty *result;
1862 + /* Read in the file */
1863 + list = grammar (fn);
1865 + result = message_list_alloc ();
1867 + /* Every reference must be matched with its definition. */
1868 + for (j = 0; j < list->nitems; ++j) {
1869 + if (list->item[j]->msgid[0] == '\0') {
1875 + /* If we don't have a header, we should try to add one */
1877 + message_list_append (result, new_header());
1879 + /* time to add the rest */
1880 + for (j = 0; j < list->nitems; ++j) {
1881 + message_ty *crtmsg;
1883 + crtmsg = list->item[j];
1884 + if (crtmsg->msgid[0] != '\0') {
1885 + /* empty the translations */
1886 + crtmsg->variant_count = 1;
1887 + crtmsg->variant[0].msgstr = "";
1890 + message_list_append (result, crtmsg);
1895 +static message_list_ty *
1897 + const char *fn; /* file name */
1899 + message_list_ty *list;
1901 + int had_header = 0;
1902 + message_list_ty *result;
1904 + /* Read in the file */
1905 + list = grammar (fn);
1907 + result = message_list_alloc ();
1909 + /* Every reference must be matched with its definition. */
1910 + for (j = 0; j < list->nitems; ++j) {
1911 + if (list->item[j]->msgid[0] == '\0') {
1917 + /* If we don't have a header, we should try to add one */
1919 + message_list_append (result, new_header());
1921 + /* time to add the rest */
1922 + for (j = 0; j < list->nitems; ++j) {
1923 + message_ty *crtmsg;
1925 + crtmsg = list->item[j];
1926 + if (crtmsg->msgid[0] != '\0') {
1927 + /* dummy translation */
1928 + crtmsg->variant_count = 1;
1929 + crtmsg->variant[0].msgstr = crtmsg->msgid;
1932 + message_list_append (result, crtmsg);
1937 +#define TM_YEAR_ORIGIN 1900
1938 +static struct message_ty *
1942 + struct tm local_time;
1945 + static lex_pos_ty pos = { __FILE__, __LINE__, };
1947 + mp = message_alloc ("");
1951 + message_comment_append (mp, "\
1952 +SOME DESCRIPTIVE TITLE.\n\
1953 +FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.\n");
1956 + local_time = *localtime (&now);
1958 + asprintf (&msgstr, "\
1959 +Project-Id-Version: PACKAGE VERSION\n\
1960 +POT-Creation-Date: %d-%02d-%02d %02d:%02d\n\
1961 +PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n\
1962 +Last-Translator: FULL NAME <EMAIL@ADDRESS>\n\
1963 +Language-Team: LANGUAGE <LL@li.org>\n\
1964 +MIME-Version: 1.0\n\
1965 +Content-Type: text/plain; charset=CHARSET\n\
1966 +Content-Transfer-Encoding: ENCODING\n",
1967 + local_time.tm_year + TM_YEAR_ORIGIN,
1968 + local_time.tm_mon + 1,
1969 + local_time.tm_mday,
1970 + local_time.tm_hour,
1971 + local_time.tm_min);
1973 + if (msgstr == NULL)
1974 + error(EXIT_FAILURE, errno, _("while preparing output"));
1975 + message_variant_append (mp, MESSAGE_DOMAIN_DEFAULT, msgstr, &pos);