]> git.pld-linux.org Git - packages/gettext.git/blame - gettext-hacks.patch
BuildRequires: libtool
[packages/gettext.git] / gettext-hacks.patch
CommitLineData
fb4f7b36 1diff -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
4@@ -19,7 +19,7 @@
5
6 AUTOMAKE_OPTIONS = 1.3 gnits
7 MAINT_CHARSET = latin1
8-ACLOCAL_AMFLAGS = -I m4
9+ACLOCAL_AMFLAGS = --acdir=m4 --acdir=$(shell aclocal --print-ac-dir)
10
11 gettextsrcdir = $(datadir)/gettext
12 gettextsrc_DATA = ABOUT-NLS
13diff -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
16@@ -12,7 +12,7 @@
17 AM_PROG_LIBTOOL
18 AC_PROG_CC
19 AC_ISC_POSIX
20-AM_PROG_INSTALL
21+AC_PROG_INSTALL
22 AC_PROG_YACC
23
24 dnl Checks for libraries.
25diff -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
28@@ -1,3 +1,3 @@
29-@set UPDATED 30 April 1998
30+@set UPDATED 21 March 1999
31 @set EDITION 0.10.35
32 @set VERSION 0.10.35
33diff -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
36@@ -1,3 +1,3 @@
37-@set UPDATED 30 April 1998
38+@set UPDATED 21 March 1999
39 @set EDITION 0.10.35
40 @set VERSION 0.10.35
c155f01f 41diff -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
44@@ -6,7 +6,7 @@
45 msgid ""
46 msgstr ""
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"
53@@ -143,23 +143,23 @@
54 msgid "Report bugs to <bug-gnu-utils@gnu.org>.\n"
55 msgstr ""
56
57-#: src/message.c:784
58+#: src/message.c:787
59 #, c-format
60 msgid ""
61 "internationalized messages should not contain the `\\%c' escape sequence"
62 msgstr ""
63
64-#: src/message.c:1115
65+#: src/message.c:1268 src/message.c:1586
66 #, c-format
67 msgid "cannot create output file \"%s\""
68 msgstr ""
69
70-#: src/message.c:1122
71+#: src/message.c:1275 src/message.c:1591
72 #, no-c-format
73 msgid "standard output"
74 msgstr ""
75
76-#: src/message.c:1182
77+#: src/message.c:1335 src/message.c:1633
78 #, c-format
79 msgid "error while writing \"%s\" file"
80 msgstr ""
fb4f7b36 81diff -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
84@@ -19,7 +19,7 @@
85
86 AUTOMAKE_OPTIONS = 1.2 gnits
87
88-bin_PROGRAMS = gettext msgcmp msgfmt msgmerge msgunfmt xgettext msgcomm
89+bin_PROGRAMS = gettext msgcmp msgfmt msgmerge msgunfmt xgettext msgcomm msghack
90
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
93@@ -52,7 +52,8 @@
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
97-
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
101
102 # Some rules for yacc handling.
103diff -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
106@@ -68,6 +68,9 @@
107 static void message_print PARAMS ((const message_ty *__mp, FILE *__fp,
108 const char *__domain, int blank_line,
109 int __debug));
110+static void master_message_print PARAMS ((const message_ty *__mp,
111+ FILE *__fp,
112+ int blank_line));
113 static void message_print_obsolete PARAMS ((const message_ty *__mp, FILE *__fp,
114 const char *__domain,
115 int blank_line));
116@@ -990,6 +993,156 @@
117
118
119 static void
120+master_message_print (mp, fp, blank_line)
121+ const message_ty *mp;
122+ FILE *fp;
123+ int blank_line;
124+{
125+ size_t j;
126+
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);
134+
135+ if (mp->comment != NULL)
136+ for (j = 0; j < mp->comment->nitems; ++j) {
137+ const unsigned char *s = mp->comment->item[j];
138+ do {
139+ const unsigned char *e;
140+ putc ('#', fp);
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
144+ contents. */
145+ if (*s != '\0' && !isspace (*s))
146+ putc (' ', fp);
147+ e = strchr (s, '\n');
148+ if (e == NULL) {
149+ fputs (s, fp);
150+ s = NULL;
151+ } else {
152+ fwrite (s, 1, e - s, fp);
153+ s = e + 1;
154+ }
155+ putc ('\n', fp);
156+ } while (s != NULL);
157+ }
158+
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];
162+ putc ('#', fp);
163+ putc ('.', fp);
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))
168+ putc (' ', fp);
169+ fputs (s, fp);
170+ putc ('\n', fp);
171+ }
172+
173+
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
177+ checked for. */
178+ if (mp->filepos_count != 0) {
179+ if (uniforum)
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] == '/')
184+ cp += 2;
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);
189+ } else {
190+ size_t column;
191+
192+ fputs ("#:", fp);
193+ column = 2;
194+ for (j = 0; j < mp->filepos_count; ++j) {
195+ lex_pos_ty *pp;
196+ char buffer[20];
197+ char *cp;
198+ size_t len;
199+
200+ pp = &mp->filepos[j];
201+ cp = pp->file_name;
202+ while (cp[0] == '.' && cp[1] == '/')
203+ cp += 2;
204+ sprintf (buffer, "%ld", (long) pp->line_number);
205+ len = strlen (cp) + strlen (buffer) + 2;
206+ if (column > 2 && column + len >= page_width)
207+ {
208+ fputs ("\n#:", fp);
209+ column = 2;
210+ }
211+ fprintf (fp, " %s:%s", cp, buffer);
212+ column += len;
213+ }
214+ putc ('\n', fp);
215+ }
216+ }
217+
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;
221+
222+ putc ('#', fp);
223+ putc (',', fp);
224+
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
227+ output. */
228+ if (mp->is_fuzzy) {
229+ fputs (" fuzzy", fp);
230+ first_flag = 0;
231+ }
232+
233+ if (significant_c_format_p (mp->is_c_format)) {
234+ if (!first_flag)
235+ putc (',', fp);
236+
237+ fputs (make_c_format_description_string (mp->is_c_format, 0),
238+ fp);
239+ first_flag = 0;
240+ }
241+
242+ if (mp->do_wrap == no) {
243+ if (!first_flag)
244+ putc (',', fp);
245+
246+ fputs (make_c_width_description_string (mp->do_wrap), fp);
247+ first_flag = 0;
248+ }
249+
250+ putc ('\n', fp);
251+ }
252+
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) {
258+ char *msgstr;
259+
260+ msgstr = malloc(strlen(mp->variant[j].domain) + 10);
261+ sprintf(msgstr, "msgstr(%s)", mp->variant[j].domain);
262+
263+ wrap (fp, NULL, msgstr, mp->variant[j].msgstr, mp->do_wrap);
264+ }
265+
266+}
267+
268+
269+static void
270 message_print_obsolete (mp, fp, domain, blank_line)
271 const message_ty *mp;
272 FILE *fp;
273@@ -1402,3 +1555,83 @@
274
275 page_width = n;
276 }
277+
278+
279+/*
280+ * HACKS... This prints a mesage list, but it uses the
281+ * msgstr(somain) syntax instead
282+ */
283+ void
284+master_list_print (mlp, filename)
285+ message_list_ty *mlp;
286+ const char *filename;
287+{
288+ FILE *fp;
289+ size_t j;
290+ int blank_line;
291+#ifdef HAVE_SETLOCALE
292+ char *old_locale;
293+#endif
294+
295+ /* We will not write anything if we have no message or only the
296+ header entry. */
297+ if (mlp->nitems == 0 || (mlp->nitems == 1 && *mlp->item[0]->msgid == '\0'))
298+ return;
299+
300+ /* Open the output file. */
301+ if (filename != NULL && strcmp (filename, "-") != 0
302+ && strcmp (filename, "/dev/stdout") != 0) {
303+ fp = fopen (filename, "w");
304+ if (fp == NULL)
305+ error (EXIT_FAILURE, errno, _("cannot create output file \"%s\""),
306+ filename);
307+ } else {
308+ fp = stdout;
309+ /* xgettext:no-c-format */
310+ filename = _("standard output");
311+ }
312+
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");
319+ if (old_locale)
320+ old_locale = xstrdup (old_locale);
321+#endif
322+
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);
327+ blank_line = 1;
328+ }
329+
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);
335+ blank_line = 1;
336+ }
337+#endif
338+
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
342+ string.) */
343+#ifdef HAVE_SETLOCALE
344+ if (old_locale) {
345+ setlocale (LC_CTYPE, old_locale);
346+ free (old_locale);
347+ }
348+#endif
349+
350+ /* Make sure nothing went wrong. */
351+ if (fflush (fp))
352+ error (EXIT_FAILURE, errno, _("error while writing \"%s\" file"),
353+ filename);
354+ fclose (fp);
355+}
356+
357diff -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
360@@ -126,4 +126,7 @@
361 int possible_c_format_p PARAMS ((enum is_c_format));
362 void message_page_width_set PARAMS ((size_t width));
363
364+/* Hacks go at the end */
365+void master_list_print PARAMS ((message_list_ty *__mlp, const char *__filename));
366+
367 #endif /* message.h */
368diff -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
c155f01f 370+++ gettext.hacked/src/msghack.c Sun Feb 27 13:30:00 2000
371@@ -0,0 +1,1606 @@
fb4f7b36 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>
375+
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)
379+ any later version.
380+
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.
385+
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. */
389+
390+#ifdef HAVE_CONFIG_H
391+# include <config.h>
392+#endif
393+
394+#include <getopt.h>
395+#include <limits.h>
396+#include <stdio.h>
397+
398+#ifdef STDC_HEADERS
399+# include <stdlib.h>
400+#endif
401+
402+#if HAVE_STRING_H
403+# include <string.h>
404+#else
405+# include <strings.h>
406+#endif
407+
408+#if HAVE_LOCALE_H
409+# include <locale.h>
410+#endif
411+
412+#include <time.h>
413+#include <errno.h>
414+
415+#include "dir-list.h"
416+#include "error.h"
417+#include "message.h"
418+#include <system.h>
419+#include <libintl.h>
420+#include "po.h"
421+
422+#define _(str) gettext (str)
423+
424+
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
429+{
430+ /* inherited instance variables, etc */
431+ PO_BASE_TY
432+
433+ /* Name of domain we are currently examining. */
434+ char *domain;
435+
436+ /* List of domains already appeared in the current file. */
437+ string_list_ty *domain_list;
438+
439+ /* List of messages already appeared in the current file. */
440+ message_list_ty *mlp;
441+
442+ /* Accumulate comments for next message directive */
443+ string_list_ty *comment;
444+ string_list_ty *comment_dot;
445+
446+ /* Flags transported in special comments. */
447+ int is_fuzzy;
448+ enum is_c_format is_c_format;
449+ enum is_c_format do_wrap;
450+
451+ /* Accumulate filepos comments for the next message directive. */
452+ size_t filepos_count;
453+ lex_pos_ty *filepos;
454+};
455+
456+
457+/* String containing name the program is called with. */
458+const char *program_name;
459+
460+/* Verbosity level. */
461+static int verbosity_level;
462+
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;
466+
467+/* Force output of PO file even if empty. */
468+static int force_po;
469+
470+/* should we merge in the fuzzy messages ? */
471+static int fuzzy = 0;
472+
c155f01f 473+/* Do we want to generate useless merges? */
474+static int useless = 0;
475+
fb4f7b36 476+/* Possible split operations */
477+#define SPLIT_MSGID 1
478+#define SPLIT_MSGSTR 2
479+static int split_flag = 0;
480+
481+/* Possible explode operations */
482+#define EXPLODE_MSGID 4
483+#define EXPLODE_MSGSTR 8
484+static int explode_flag = 0;
485+
486+/* Sort orders */
487+#define SORT_BY_FILEPOS 1
488+#define SORT_BY_MSGID 2
489+static int sort_order = 0;
490+
c155f01f 491+/* Other flags */
492+static int comments = 0;
493+
fb4f7b36 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,
509+ int __line));
510+static message_list_ty *grammar PARAMS ((const char *__filename));
c155f01f 511+static message_list_ty *append PARAMS ((const char *__fn1, const char *__fn2, int diff_only));
fb4f7b36 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));
c155f01f 517+static message_list_ty *dummy PARAMS ((const char *__fn));
fb4f7b36 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));
c155f01f 523+static struct message_ty *new_header PARAMS((void));
fb4f7b36 524+
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
c155f01f 536+#define ACTION_DO_DUMMY 11
537+#define ACTION_DO_DIFF 12
fb4f7b36 538+
539+int main (argc, argv)
540+ int argc;
541+ char **argv;
542+{
543+ int opt;
544+ int do_action = 0;
545+ char *output_file;
546+ message_list_ty *result;
547+
548+ /* Long options. */
549+ const struct option long_options[] =
550+ {
551+ /* command pairs */
552+ { "split-id", no_argument, &split_flag, SPLIT_MSGID },
553+ { "split-str", no_argument, &split_flag, SPLIT_MSGSTR },
554+
555+ { "explode-id", required_argument, &explode_flag, EXPLODE_MSGID },
556+ { "explode-str", required_argument, &explode_flag, EXPLODE_MSGSTR },
557+
558+ { "sort-by-file", no_argument, &sort_order, SORT_BY_FILEPOS },
559+ { "sort-by-id", no_argument, &sort_order, SORT_BY_MSGID },
560+
561+ /* flags */
c155f01f 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 },
fb4f7b36 567+
c155f01f 568+ /*
569+ * ACTIONS
570+ */
571+ /* switch the msgid and the msgstr strings in a PO file */
fb4f7b36 572+ { "invert", no_argument, &do_action, ACTION_DO_INVERT },
c155f01f 573+
574+ /* fill the msgstr with the contents of msgid */
575+ { "dummy", no_argument, &do_action, ACTION_DO_DUMMY },
576+
577+ /* merge two files based on commin msgid. The msgid is stored as a comment */
fb4f7b36 578+ { "merge", no_argument, &do_action, ACTION_DO_MERGE },
c155f01f 579+
580+ /* strip out the msgstr creating a POT form a PO file */
fb4f7b36 581+ { "empty", no_argument, &do_action, ACTION_DO_EMPTY },
c155f01f 582+
583+ /* combine sevaral PO files into a "master" catalog */
fb4f7b36 584+ { "master", no_argument, &do_action, ACTION_DO_MASTER },
c155f01f 585+
586+ /* append entries from ref POT that do not exist in file PO */
fb4f7b36 587+ { "append", no_argument, &do_action, ACTION_DO_APPEND },
c155f01f 588+
589+ /* show only stuff from ref POT that does not exist in file PO */
590+ { "diff", no_argument, &do_action, ACTION_DO_DIFF },
591+
592+ /* ommit comments for the 'append' and 'diff' */
593+ { "comments", no_argument, &comments, 1 },
594+
595+ /* remove duplicates */
fb4f7b36 596+ { "unduplicate", no_argument, &do_action, ACTION_DO_UNDUP },
c155f01f 597+
598+ /* output strings that need translation (fuzzies and untranslated */
fb4f7b36 599+ { "missing", no_argument, &do_action, ACTION_DO_MISSING },
600+
c155f01f 601+ /* output strings that need translation (fuzzies and untranslated */
602+ { "missing", no_argument, &do_action, ACTION_DO_MISSING },
603+
604+ /* INFO */
fb4f7b36 605+ { "help", no_argument, NULL, 'h' },
606+ { "version", no_argument, NULL, 'V' },
607+
608+ { NULL, 0, NULL, 0 }
609+ };
610+
611+
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;
617+
618+#ifdef HAVE_SETLOCALE
619+ /* Set locale via LC_ALL. */
620+ setlocale (LC_ALL, "");
621+#endif
622+
623+ /* Set the text message domain. */
624+ bindtextdomain (PACKAGE, LOCALEDIR);
625+ textdomain (PACKAGE);
626+
627+ /* Set default values for variables. */
628+ output_file = NULL;
629+
630+ while ((opt
631+ = getopt_long (argc, argv, "ho:Vw:v", long_options, NULL))
632+ != EOF)
633+ switch (opt) {
634+ case '\0': /* Long option. */
635+ break;
636+
637+ case 'h':
638+ /* Help is requested. */
639+ usage (EXIT_SUCCESS);
640+ break;
641+
642+ case 'o':
643+ output_file = optarg;
644+ break;
645+
646+ case 'v':
647+ ++verbosity_level;
648+ break;
649+
650+ case 'V':
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);
660+ break;
661+
662+ case 'w':
663+ {
664+ int value;
665+ char *endp;
666+ value = strtol (optarg, &endp, 10);
667+ if (endp != optarg)
668+ message_page_width_set (value);
669+ }
670+ break;
671+
672+ default:
673+ usage (EXIT_FAILURE);
674+ break;
675+ }
676+
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);
681+ }
682+
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;
690+
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]);
697+ break;
698+ case ACTION_DO_EMPTY:
699+ /* we are asked to delete the msgstr text in a .po file */
700+ result = empty (argv[optind]);
701+ break;
c155f01f 702+ case ACTION_DO_DUMMY:
703+ /* dummy out a POT file in a PO file (msgstr = msgid) */
704+ result = dummy (argv[optind]);
705+ break;
fb4f7b36 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 */
710+ break;
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);
714+ break;
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);
720+ }
721+ result = merge (argv[optind], argv[optind+1]);
722+ break;
c155f01f 723+ case ACTION_DO_DIFF:
fb4f7b36 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);
730+ }
c155f01f 731+ result = append (argv[optind], argv[optind+1], do_action == ACTION_DO_DIFF);
fb4f7b36 732+ break;
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);
739+ break;
740+ case ACTION_DO_MASTER:
741+ /* This is a little bit funkier:
742+ * Suppose in A.po we have:
743+ * msgid "id"
744+ * msgstr "str1"
745+ * And in B.po we have:
746+ * msgid "id"
747+ * msgstr "str2"
748+ * then the result will look like:
749+ * msgid "id"
750+ * msgstr(A) "str1"
751+ * msgstr(B) "str2"
752+ */
753+ result = NULL; /* Start from scratch */
754+ for (opt = optind ; opt < argc ; opt++) {
755+ char *file_name, *master_id;
756+ char *tmp;
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, '.');
761+ if (tmp == NULL) {
762+ error (EXIT_SUCCESS, 0,
763+ _("Message catalog %s does not have a valid name"), argv[opt]);
764+ usage (EXIT_FAILURE);
765+ }
766+ *tmp = '\0';
767+ result = master(&result, file_name, master_id);
768+ }
769+ master_list_print(result, output_file);
770+ return EXIT_SUCCESS;
771+ break;
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]);
776+ break;
777+ case ACTION_DO_MISSING:
778+ /* generate a new po file of only the missing and non-translated strings */
779+ result = missing (argv[optind]);
780+ break;
781+ default:
782+ error (EXIT_SUCCESS, 0, _("Unknown Action"));
783+ exit(EXIT_FAILURE);
784+ }
785+
786+ /* Sort the results. */
787+ switch (sort_order) {
788+ case SORT_BY_FILEPOS:
789+ message_list_sort_by_filepos (result);
790+ break;
791+ case SORT_BY_MSGID:
792+ message_list_sort_by_msgid (result);
793+ break;
794+ }
795+
796+ /* Write the merged message list out. */
797+ message_list_print (result, output_file, force_po, 0);
798+
799+ exit (EXIT_SUCCESS);
800+}
801+
802+
803+/* Display usage information and exit. */
804+static void
805+usage (status)
806+ int status;
807+{
808+ if (status != EXIT_SUCCESS)
809+ fprintf (stderr, _("Try `%s --help' for more information.\n"),
810+ program_name);
811+ else {
812+ /* xgettext: no-wrap */
813+ printf (_("\
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\
c155f01f 827+ + --useless also generate entries for unmatched pairs.\n\
fb4f7b36 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\
c155f01f 831+ --dummy create a .po file from a .pot by doing msgstr = msgid\n\
fb4f7b36 832+ --append append entries from ref.po that don't exist in file.po\n\
c155f01f 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\
fb4f7b36 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\
839+\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\
842+"), program_name);
843+ }
844+ exit (status);
845+}
846+
847+
848+/* The address of this function will be assigned to the hook in the
849+ error functions. */
850+static void error_print ()
851+{
852+ /* We don't want the program name to be printed in messages. Emacs'
853+ compile.el does not like this. */
854+
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 */
857+}
858+
859+
860+static void
861+merge_constructor (that)
862+ po_ty *that;
863+{
864+ merge_class_ty *this = (merge_class_ty *) that;
865+
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;
876+}
877+
878+
879+static void
880+merge_destructor (that)
881+ po_ty *that;
882+{
883+ merge_class_ty *this = (merge_class_ty *) that;
884+ size_t j;
885+
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);
896+}
897+
898+
899+static void
900+merge_directive_domain (that, name)
901+ po_ty *that;
902+ char *name;
903+{
904+ size_t j;
905+
906+ merge_class_ty *this = (merge_class_ty *) that;
907+ /* Override current domain name. Don't free memory. */
908+ this->domain = name;
909+
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)
914+ {
915+ string_list_free (this->comment);
916+ this->comment = NULL;
917+ }
918+ if (this->comment_dot != NULL)
919+ {
920+ string_list_free (this->comment_dot);
921+ this->comment_dot = NULL;
922+ }
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;
929+}
930+
931+
932+static void
933+merge_directive_message (that, msgid, msgid_pos, msgstr, msgstr_pos)
934+ po_ty *that;
935+ char *msgid;
936+ lex_pos_ty *msgid_pos;
937+ char *msgstr;
938+ lex_pos_ty *msgstr_pos;
939+{
940+ merge_class_ty *this = (merge_class_ty *) that;
941+ message_ty *mp;
942+ message_variant_ty *mvp;
943+ size_t j;
944+
945+ /* Remember the domain names for later. */
946+ string_list_append_unique (this->domain_list, this->domain);
947+
948+ /* See if this message ID has been seen before. */
949+ mp = message_list_search (this->mlp, msgid);
950+ if (mp)
951+ free (msgid);
952+ else
953+ {
954+ mp = message_alloc (msgid);
955+ message_list_append (this->mlp, mp);
956+ }
957+
958+ /* Add the accumulated comments to the message. Clear the
959+ accumulation in preparation for the next message. */
960+ if (this->comment != NULL)
961+ {
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;
966+ }
967+ if (this->comment_dot != NULL)
968+ {
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;
973+ }
974+ for (j = 0; j < this->filepos_count; ++j)
975+ {
976+ lex_pos_ty *pp;
977+
978+ pp = &this->filepos[j];
979+ message_comment_filepos (mp, pp->file_name, pp->line_number);
980+ free (pp->file_name);
981+ }
982+ mp->is_fuzzy = this->is_fuzzy;
983+ mp->is_c_format = this->is_c_format;
984+ mp->do_wrap = this->do_wrap;
985+
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;
993+
994+ /* See if this domain has been seen for this message ID. */
995+ mvp = message_variant_search (mp, this->domain);
996+ if (mvp)
997+ {
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"));
1001+ free (msgstr);
1002+ }
1003+ else
1004+ message_variant_append (mp, this->domain, msgstr, msgstr_pos);
1005+}
1006+
1007+
1008+static void
1009+merge_parse_brief (that)
1010+ po_ty *that;
1011+{
1012+ po_lex_pass_comments (1);
1013+}
1014+
1015+
1016+static void
1017+merge_parse_debrief (that)
1018+ po_ty *that;
1019+{
1020+ merge_class_ty *this = (merge_class_ty *) that;
1021+ message_list_ty *mlp = this->mlp;
1022+ size_t j;
1023+
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)
1027+ {
1028+ const char *domain_name;
1029+ size_t k;
1030+
1031+ domain_name = this->domain_list->item[j];
1032+ for (k = 0; k < mlp->nitems; ++k)
1033+ {
1034+ const message_ty *mp;
1035+ size_t m;
1036+
1037+ mp = mlp->item[k];
1038+ for (m = 0; m < mp->variant_count; ++m)
1039+ {
1040+ message_variant_ty *mvp;
1041+
1042+ mvp = &mp->variant[m];
1043+ if (strcmp (domain_name, mvp->domain) == 0)
1044+ break;
1045+ }
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);
1049+ }
1050+ }
1051+}
1052+
1053+
1054+static void
1055+merge_comment (that, s)
1056+ po_ty *that;
1057+ const char *s;
1058+{
1059+ merge_class_ty *this = (merge_class_ty *) that;
1060+
1061+ if (this->comment == NULL)
1062+ this->comment = string_list_alloc ();
1063+ string_list_append (this->comment, s);
1064+}
1065+
1066+
1067+static void
1068+merge_comment_dot (that, s)
1069+ po_ty *that;
1070+ const char *s;
1071+{
1072+ merge_class_ty *this = (merge_class_ty *) that;
1073+
1074+ if (this->comment_dot == NULL)
1075+ this->comment_dot = string_list_alloc ();
1076+ string_list_append (this->comment_dot, s);
1077+}
1078+
1079+
1080+static void
1081+merge_comment_special (that, s)
1082+ po_ty *that;
1083+ const char *s;
1084+{
1085+ merge_class_ty *this = (merge_class_ty *) that;
1086+
1087+ if (strstr (s, "fuzzy") != NULL)
1088+ this->is_fuzzy = 1;
1089+
1090+ this->is_c_format = parse_c_format_description_string (s);
1091+ this->do_wrap = parse_c_width_description_string (s);
1092+}
1093+
1094+
1095+static void
1096+merge_comment_filepos (that, name, line)
1097+ po_ty *that;
1098+ const char *name;
1099+ int line;
1100+{
1101+ merge_class_ty *this = (merge_class_ty *) that;
1102+ size_t nbytes;
1103+ lex_pos_ty *pp;
1104+
1105+ if (!line_comment)
1106+ return;
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;
1112+}
1113+
1114+
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. */
1120+
1121+static po_method_ty merge_methods =
1122+{
1123+ sizeof (merge_class_ty),
1124+ merge_constructor,
1125+ merge_destructor,
1126+ merge_directive_domain,
1127+ merge_directive_message,
1128+ merge_parse_brief,
1129+ merge_parse_debrief,
1130+ merge_comment,
1131+ merge_comment_dot,
1132+ merge_comment_filepos,
1133+ merge_comment_special
1134+};
1135+
1136+
1137+static message_list_ty *
1138+grammar (filename)
1139+ const char *filename;
1140+{
1141+ po_ty *pop;
1142+ message_list_ty *mlp;
1143+
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;
1148+ po_free (pop);
1149+ return mlp;
1150+}
1151+
1152+
1153+#define DOT_FREQUENCE 10
1154+
1155+/*
1156+ * Given two meta files (m,X) and (m,N) generate a po file (N,X)
1157+ * preserving the meta information in special comments
1158+ */
1159+static message_list_ty *
1160+merge (fn1, fn2)
1161+ const char *fn1; /* definitions */
1162+ const char *fn2; /* references */
1163+{
1164+ message_list_ty *def;
1165+ message_list_ty *ref;
1166+ message_ty *defmsg;
1167+ size_t j, k;
1168+ size_t merged, fuzzied, missing, obsolete;
1169+ message_list_ty *result;
1170+
1171+ /* This is the definitions file, created by a human. */
1172+ def = grammar (fn1);
1173+
1174+ /* This is the references file, created by groping the sources with
1175+ * the xgettext program. */
1176+ ref = grammar (fn2);
1177+
1178+ result = message_list_alloc ();
1179+
1180+ /* Every reference must be matched with its definition. */
1181+ for (j = 0; j < ref->nitems; ++j) {
1182+ message_ty *refmsg;
1183+
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);
1188+
1189+ refmsg = ref->item[j];
1190+
1191+ /* See if it is in the other file. */
1192+ defmsg = message_list_search (def, refmsg->msgid);
1193+ if (defmsg) {
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);
1199+
c155f01f 1200+ if (mp != NULL)
1201+ message_list_append (result, mp);
fb4f7b36 1202+
1203+ /* Remember that this message has been used, when we scan
1204+ later to see if anything was omitted. */
1205+ defmsg->used = 1;
1206+ ++merged;
1207+ continue;
c155f01f 1208+ } else if (useless) {
fb4f7b36 1209+ message_ty *mp;
1210+ const char *tmp;
1211+ if (verbosity_level > 1)
1212+ gram_error_at_line (&refmsg->variant[0].pos,
1213+ _("this message is used but not defined in %s"),
1214+ fn1);
1215+
1216+ /* Insert the blank record */
1217+ mp = message_copy (refmsg);
1218+ tmp = mp->msgid;
1219+ mp->msgid = mp->variant[0].msgstr;
1220+ mp->variant[0].msgstr = "";
1221+ message_list_append (result, mp);
1222+ ++missing;
1223+ }
1224+ }
1225+
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. */
c155f01f 1229+ if (useless)
1230+ for (k = 0; k < def->nitems; ++k) {
1231+ defmsg = def->item[k];
1232+ if (defmsg->used)
1233+ continue;
fb4f7b36 1234+
c155f01f 1235+ /* Remember the old translation although it is not used anymore.
1236+ But we mark it as obsolete. */
1237+ defmsg->obsolete = 1;
fb4f7b36 1238+
c155f01f 1239+ message_list_append (result, defmsg);
1240+ ++obsolete;
1241+ }
fb4f7b36 1242+
1243+ /* Report some statistics. */
1244+ if (verbosity_level > 0)
1245+ fprintf (stderr,
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);
1251+
1252+ /* get rid of the duplicate message ids */
1253+ return un_duplicate(result);
1254+}
1255+
1256+/*
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.
1260+ */
1261+static message_list_ty *
c155f01f 1262+append (fn1, fn2, diff_only)
fb4f7b36 1263+ const char *fn1; /* base file */
1264+ const char *fn2; /* more stuff found in here */
c155f01f 1265+ int diff_only; /* do we want only the diffs? */
fb4f7b36 1266+{
1267+ message_list_ty *ml1;
1268+ message_list_ty *ml2;
c155f01f 1269+ message_list_ty *result;
fb4f7b36 1270+ size_t j;
1271+ size_t added = 0;
1272+ int initial;
1273+
1274+ /* This is the definitions file, created by a human. */
1275+ ml1 = grammar (fn1);
1276+ initial = ml1->nitems;
1277+
1278+ /* This is the references file, created by groping the sources with
1279+ * the xgettext program. */
1280+ ml2 = grammar (fn2);
1281+
c155f01f 1282+ result = message_list_alloc();
1283+
fb4f7b36 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;
1288+ int i;
1289+
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);
1294+
1295+ /* this is the message we want to add */
1296+ newmsg = ml2->item[j];
1297+
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 */
c155f01f 1301+ message_list_append (result, newmsg);
fb4f7b36 1302+ newmsg->used = 1;
1303+ ++added;
1304+ continue;
1305+ }
c155f01f 1306+
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]);
fb4f7b36 1312+
c155f01f 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]);
fb4f7b36 1316+
c155f01f 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);
1321+ }
fb4f7b36 1322+ }
1323+ newmsg->used++;
1324+ }
1325+
1326+ /* Report some statistics. */
1327+ if (verbosity_level > 0)
1328+ fprintf (stderr,
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);
1334+
c155f01f 1335+ /* do we want only the diffs? */
1336+ if (diff_only) {
1337+ return result;
1338+ }
1339+
1340+ /* append the result to ml1 */
1341+ for (j = 0; j < result->nitems; ++j)
1342+ message_list_append(ml1, result->item[j]);
1343+
1344+ /* No need to free the result since message_list_alloc copies only the
1345+ references over */
fb4f7b36 1346+ return ml1;
1347+}
1348+
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) */
1354+{
1355+ message_list_ty *list;
1356+ message_list_ty *result;
1357+ int j;
1358+
1359+ /* Read in the file */
1360+ list = grammar (fn);
1361+
1362+ if (*prev == NULL)
1363+ *prev = message_list_alloc ();
1364+
1365+ result = *prev; /* Work with that */
1366+
1367+ /* Every reference must be matched with its definition. */
1368+ for (j = 0; j < list->nitems; ++j) {
1369+ message_ty *crtmsg, *merge_msg;
1370+
1371+ /* check for empty message ids == headers */
1372+ if (list->item[j]->msgid[0] == '\0') {
1373+ continue;
1374+ }
1375+
1376+ if ((list->item[j])->is_fuzzy && (fuzzy == 0)) {
1377+ /* we don't want fuzzies */
1378+ continue;
1379+ }
1380+
1381+ crtmsg = message_copy (list->item[j]);
1382+
1383+ /* First, search its pair in the result list ... */
1384+ merge_msg = message_list_search (result, crtmsg->msgid);
1385+
1386+ /* Now here is something broken: we get only the msgstr
1387+ * from the variant[0] and override its domain with our master_id
1388+ */
1389+ crtmsg->variant_count = 1;
1390+ crtmsg->variant[0].domain = master_id;
1391+
1392+ if (merge_msg != NULL) {
1393+ int variants;
1394+ void *temp;
1395+
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;
1401+ } else {
1402+ error (EXIT_FAILURE, 0, "OUT of memory in %s", __FUNCTION__);
1403+ exit(-1);
1404+ }
1405+ merge_msg->variant[variants-1] = crtmsg->variant[0];
1406+ /* that should be it */
1407+ } else {
1408+ /* this is really simple - just add it */
1409+ message_list_append (result, crtmsg);
1410+ }
1411+
1412+ /* Remember that this message has been used, when we scan
1413+ later to see if anything was omitted. */
1414+ crtmsg->used = 1;
1415+ }
1416+
1417+ return result ;
1418+}
1419+
1420+static message_list_ty *
1421+invert (fn)
1422+ const char *fn; /* file name */
1423+{
1424+ message_list_ty *list;
1425+ size_t j;
1426+ size_t inverted = 0;
1427+ message_list_ty *result;
1428+
1429+ /* Read in the file */
1430+ list = grammar (fn);
1431+
1432+ result = message_list_alloc ();
1433+
1434+ /* Every reference must be matched with its definition. */
1435+ for (j = 0; j < list->nitems; ++j) {
1436+ message_ty *crtmsg;
1437+ int k;
1438+
1439+ /* check for empty message ids == headers */
1440+ if (list->item[j]->msgid[0] == '\0') {
1441+ message_list_append (result, list->item[j]);
1442+ continue;
1443+ }
1444+
1445+ crtmsg = message_copy (list->item[j]);
1446+
1447+ /*
1448+ * Now invert it. For each domain found in the file we create a record
1449+ * containing the inverted pair
1450+ */
1451+ for (k = 0; k < crtmsg->variant_count; k++) {
1452+ message_ty *mp;
1453+ const char *tmp;
1454+
1455+ mp = message_copy(crtmsg);
1456+ mp->variant_count = 1;
1457+ tmp = mp->msgid;
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);
1462+ ++inverted;
1463+ }
1464+
1465+ /* Remember that this message has been used, when we scan
1466+ later to see if anything was omitted. */
1467+ crtmsg->used = 1;
1468+ }
1469+
1470+ /* get rid of the duplicate message ids */
1471+ return un_duplicate(result);
1472+}
1473+
1474+static message_list_ty *
1475+missing (fn)
1476+ const char *fn; /* file name */
1477+{
1478+ message_list_ty *list;
1479+ size_t j;
1480+ message_list_ty *result;
1481+
1482+ /* Read in the file */
1483+ list = grammar (fn);
1484+
1485+ result = message_list_alloc ();
1486+
1487+ /* Every reference must be matched with its definition. */
1488+ for (j = 0; j < list->nitems; ++j) {
1489+ int k;
1490+
1491+ /* check for empty message ids == headers */
1492+ if (list->item[j]->msgid[0] == '\0') {
1493+ message_list_append (result, list->item[j]);
1494+ continue;
1495+ }
1496+
1497+ /* Fuzzies go in */
1498+ if (list->item[j]->is_fuzzy) {
1499+ message_list_append (result, list->item[j]);
1500+ continue;
1501+ }
1502+
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]);
1507+ break;
1508+ }
1509+ }
1510+
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;
1514+ }
1515+ return result;
1516+}
1517+
1518+static message_list_ty *
1519+un_duplicate (dup_list)
1520+ message_list_ty *dup_list; /* list containing duplicates */
1521+{
1522+ message_list_ty *result;
1523+ size_t j;
1524+
1525+ result = message_list_alloc ();
1526+
1527+ /* First iteration, clear the used flag */
1528+ for (j = 0; j < dup_list->nitems; ++j)
1529+ dup_list->item[j]->used = 0;
1530+
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;
1537+ size_t k;
1538+
1539+ /* get the current message */
1540+ crtmsg = dup_list->item[j];
1541+
1542+ if (crtmsg->used > 0)
1543+ continue;
1544+
1545+ for (k = j + 1; k < dup_list->nitems; ++k) {
1546+ message_ty *newmsg;
1547+ size_t i;
1548+
1549+ newmsg = dup_list->item[k];
1550+
1551+ if (strcmp(crtmsg->msgid, newmsg->msgid) != 0 ||
1552+ newmsg->used > 0)
1553+ continue;
1554+
1555+ if (newmsg->comment)
1556+ for (i = 0; i < newmsg->comment->nitems; ++i)
1557+ message_comment_append (crtmsg, newmsg->comment->item[i]);
1558+
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]);
1562+
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);
1567+ }
1568+
1569+ fprintf(stderr, "%05d : %05d\r", j, k);
1570+ /* Now mark it as used */
1571+ newmsg->used++;
1572+ }
1573+
1574+ /* Now put the resulting entry on the final list */
1575+ message_list_append (result, crtmsg);
1576+ }
1577+
1578+ return result;
1579+
1580+}
1581+
1582+message_ty *
1583+message_join (def, ref)
1584+ message_ty *def;
1585+ message_ty *ref;
1586+{
1587+ message_ty *result;
1588+ size_t j;
1589+ char *meta_comment;
1590+
1591+ /* is this the header ? */
1592+ if (ref->msgid[0] == '\0') {
1593+ result = message_copy(ref);
1594+ return result;
1595+ };
1596+
1597+
1598+ /* XXX: FIX ME!!!
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
1602+ */
1603+
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;
1608+
c155f01f 1609+ if (!useless) {
1610+ /* Trim down on crap translations */
1611+ if (result->variant[0].msgstr == NULL)
1612+ return NULL;
1613+ if (strlen(result->variant[0].msgstr) == 0)
1614+ return NULL;
1615+ if (strcmp(result->msgid, result->variant[0].msgstr) == 0)
1616+ return NULL;
1617+ }
1618+
fb4f7b36 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.
1621+ */
1622+ /* we don't do that here because result is already initialized from def
1623+ --cristiang */
1624+ /*if (def->comment) */
1625+ /* for (j = 0; j < def->comment->nitems; ++j) */
1626+ /* message_comment_append (result, def->comment->item[j]); */
1627+
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);
1634+ } else {
1635+ message_comment_append(result, "meta=ERROR!!!");
1636+ message_comment_append(result, ref->msgid);
1637+ }
1638+
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]);
1645+
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;
1653+
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);
1660+ }
1661+
1662+ /* All done, return the merged message to the caller. */
1663+ return result;
1664+}
1665+
1666+static message_list_ty *
1667+split (fn, flag)
1668+ const char *fn; /* file name */
1669+ int flag; /* what should we be splitting out */
1670+{
1671+ message_list_ty *list;
1672+ size_t j;
1673+ message_list_ty *result;
1674+
1675+ /* Read in the file */
1676+ list = grammar (fn);
1677+
1678+ result = message_list_alloc ();
1679+
1680+ /* Every reference must be matched with its definition. */
1681+ for (j = 0; j < list->nitems; ++j) {
1682+ message_ty *crtmsg;
1683+
1684+ /* get the current message */
1685+ crtmsg = message_copy (list->item[j]);
1686+
1687+ /* search all comments looking for our meta= */
1688+ if (crtmsg->comment) {
1689+ int k;
1690+ for (k = 0; k < crtmsg->comment->nitems; ++k) {
1691+ char *tmp;
1692+
1693+ tmp = strstr(crtmsg->comment->item[k], "meta=");
1694+ if (tmp != NULL) { /* found it */
1695+ message_ty *res;
1696+ int i;
1697+ message_variant_ty *mvp = NULL;
1698+
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);
1705+ }
1706+ *mvp = crtmsg->variant[0];
1707+ res->variant = mvp;
1708+ switch(flag) {
1709+ case SPLIT_MSGID:
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]);
1715+ break;
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)
1721+ if (i != k)
1722+ message_comment_append(res, crtmsg->comment->item[i]);
1723+ break;
1724+ default:
1725+ error (EXIT_SUCCESS, 0, _("Unknwon split mode"));
1726+ usage (EXIT_FAILURE);
1727+ }
1728+ message_list_append (result, res);
1729+ }
1730+ }
1731+ } else {
1732+ /* we have no meta comment on this one */
1733+ continue;
1734+ }
1735+ }
1736+ return result;
1737+}
1738+
1739+static message_list_ty *
1740+explode (fn, flag)
1741+ const char *fn; /* file name */
1742+ int flag; /* what should we be splitting out */
1743+{
1744+ message_list_ty *list;
1745+ size_t j;
1746+ message_list_ty *result;
1747+
1748+ /* Read in the file */
1749+ list = grammar (fn);
1750+
1751+ result = message_list_alloc ();
1752+
1753+ /* Every reference ... */
1754+ for (j = 0; j < list->nitems; ++j) {
1755+ message_ty *crtmsg;
1756+ int k;
1757+
1758+ /* Get the current message */
1759+ crtmsg = message_copy (list->item[j]);
1760+
1761+ /* Every "conformant" cross reference ... */
1762+ for (k = 0; k < crtmsg->filepos_count; ++k) {
1763+ lex_pos_ty *pp;
1764+ char buf[1024];
1765+ const char *fn, *tn;
1766+ const char *f, *fe;
1767+ int ln;
1768+ message_ty *res;
1769+ int i;
1770+ message_variant_ty *mvp = NULL;
1771+
1772+ pp = &crtmsg->filepos[k];
1773+ fn = pp->file_name;
1774+ ln = pp->line_number;
1775+
1776+ switch(ln) {
1777+ default:
1778+ tn = NULL;
1779+ break;
1780+ case 1004:
1781+ tn = "(Summary)";
1782+ break;
1783+ case 1005:
1784+ tn = "(Description)";
1785+ break;
1786+ case 1016:
1787+ tn = "(Group)";
1788+ break;
1789+ }
1790+
1791+ /* ... weird tags we do not want */
1792+ if (tn == NULL)
1793+ continue;
1794+
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);
1799+ continue;
1800+ }
1801+ fe = fn + strlen(fn) - sizeof(".src.rpm") + 1;
1802+
1803+ /* ... src.rpm's we do not want */
1804+ if ( !strcmp(fe, ".src.rpm") )
1805+ continue;
1806+
1807+ /* Position at end of name */
1808+ fe = strrchr(fn, '-') - 1;
1809+ while (fe > fn && *fe != '-')
1810+ --fe;
1811+
1812+ /* Construct meta tag */
1813+ strncpy(buf, fn, (fe-fn) );
1814+ buf[fe-fn] = '\0';
1815+ strncat(buf, tn, (sizeof(buf) - strlen(buf)) );
1816+
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);
1823+ }
1824+ *mvp = crtmsg->variant[0];
1825+ res->variant = mvp;
1826+ switch(flag) {
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]);
1833+ break;
1834+ case EXPLODE_MSGSTR:
1835+ res->variant[0].msgstr = crtmsg->variant[0].msgstr;
1836+#if 0
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]);
1841+#endif
1842+ break;
1843+ default:
1844+ error (EXIT_SUCCESS, 0, _("Unknwon explode mode"));
1845+ usage (EXIT_FAILURE);
1846+ }
1847+ message_list_append (result, res);
1848+ }
1849+ }
1850+ return result;
1851+}
1852+
fb4f7b36 1853+static message_list_ty *
1854+empty (fn)
1855+ const char *fn; /* file name */
1856+{
1857+ message_list_ty *list;
1858+ size_t j;
1859+ int had_header = 0;
1860+ message_list_ty *result;
1861+
1862+ /* Read in the file */
1863+ list = grammar (fn);
1864+
1865+ result = message_list_alloc ();
1866+
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') {
1870+ had_header++;
1871+ break;
1872+ }
1873+ }
1874+
1875+ /* If we don't have a header, we should try to add one */
c155f01f 1876+ if (!had_header)
1877+ message_list_append (result, new_header());
1878+
1879+ /* time to add the rest */
1880+ for (j = 0; j < list->nitems; ++j) {
1881+ message_ty *crtmsg;
1882+
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 = "";
1888+ }
1889+ crtmsg->used = 1;
1890+ message_list_append (result, crtmsg);
1891+ }
1892+ return result;
1893+}
1894+
1895+static message_list_ty *
1896+dummy (fn)
1897+ const char *fn; /* file name */
1898+{
1899+ message_list_ty *list;
1900+ size_t j;
1901+ int had_header = 0;
1902+ message_list_ty *result;
1903+
1904+ /* Read in the file */
1905+ list = grammar (fn);
1906+
1907+ result = message_list_alloc ();
1908+
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') {
1912+ had_header++;
1913+ break;
1914+ }
1915+ }
1916+
1917+ /* If we don't have a header, we should try to add one */
1918+ if (!had_header)
1919+ message_list_append (result, new_header());
1920+
1921+ /* time to add the rest */
1922+ for (j = 0; j < list->nitems; ++j) {
1923+ message_ty *crtmsg;
1924+
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;
1930+ }
1931+ crtmsg->used = 1;
1932+ message_list_append (result, crtmsg);
1933+ }
1934+ return result;
1935+}
1936+
1937+#define TM_YEAR_ORIGIN 1900
1938+static struct message_ty *
1939+new_header(void)
1940+{
fb4f7b36 1941+ time_t now;
1942+ struct tm local_time;
1943+ message_ty *mp;
1944+ char *msgstr;
1945+ static lex_pos_ty pos = { __FILE__, __LINE__, };
1946+
1947+ mp = message_alloc ("");
c155f01f 1948+ if (mp == NULL)
1949+ return NULL;
1950+
fb4f7b36 1951+ message_comment_append (mp, "\
1952+SOME DESCRIPTIVE TITLE.\n\
1953+FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.\n");
1954+
1955+ time (&now);
1956+ local_time = *localtime (&now);
1957+
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);
1972+
1973+ if (msgstr == NULL)
1974+ error(EXIT_FAILURE, errno, _("while preparing output"));
1975+ message_variant_append (mp, MESSAGE_DOMAIN_DEFAULT, msgstr, &pos);
c155f01f 1976+ return mp;
fb4f7b36 1977+}
This page took 0.25143 seconds and 4 git commands to generate.