]> git.pld-linux.org Git - packages/gettext.git/blob - gettext-hacks.patch
added patch for parsing dml {{ }}. rel++
[packages/gettext.git] / gettext-hacks.patch
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
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
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
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.
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
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
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
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
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
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 ""
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
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.
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
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 +
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
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 */
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
371 @@ -0,0 +1,1606 @@
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 +
473 +/* Do we want to generate useless merges? */
474 +static int useless = 0;
475 +
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 +
491 +/* Other flags */
492 +static int comments = 0;
493 +
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));
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));
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
536 +#define ACTION_DO_DUMMY               11
537 +#define ACTION_DO_DIFF        12
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 */
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 }, 
567 +
568 +       /*
569 +        *  ACTIONS
570 +        */
571 +       /* switch the msgid and the msgstr strings in a PO file */
572 +       { "invert",      no_argument, &do_action, ACTION_DO_INVERT },
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 */
578 +       { "merge",       no_argument, &do_action, ACTION_DO_MERGE }, 
579 +
580 +       /* strip out the msgstr creating a POT form a PO file */
581 +       { "empty",       no_argument, &do_action, ACTION_DO_EMPTY }, 
582 +
583 +       /* combine sevaral PO files into a "master" catalog */
584 +       { "master",      no_argument, &do_action, ACTION_DO_MASTER },
585 +
586 +       /* append entries from ref POT that do not exist in file PO */
587 +       { "append",      no_argument, &do_action, ACTION_DO_APPEND },
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 */
596 +       { "unduplicate", no_argument, &do_action, ACTION_DO_UNDUP },
597 +
598 +       /* output strings that need translation (fuzzies and untranslated */
599 +       { "missing",     no_argument, &do_action, ACTION_DO_MISSING },
600 +
601 +       /* output strings that need translation (fuzzies and untranslated */
602 +       { "missing",     no_argument, &do_action, ACTION_DO_MISSING },
603 +       
604 +       /* INFO */
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;
702 +       case ACTION_DO_DUMMY:
703 +           /* dummy out a POT file in a PO file (msgstr = msgid) */
704 +           result = dummy (argv[optind]);
705 +           break;
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;
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);
730 +           }      
731 +           result = append (argv[optind], argv[optind+1], do_action == ACTION_DO_DIFF);
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\
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\
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 +
1200 +           if (mp != NULL)
1201 +               message_list_append (result, mp);
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;
1208 +       } else if (useless) {
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.  */
1229 +    if (useless)
1230 +       for (k = 0; k < def->nitems; ++k) {
1231 +           defmsg = def->item[k];
1232 +           if (defmsg->used)
1233 +               continue;
1234 +
1235 +           /* Remember the old translation although it is not used anymore.
1236 +              But we mark it as obsolete.  */
1237 +           defmsg->obsolete = 1;
1238 +
1239 +           message_list_append (result, defmsg);
1240 +           ++obsolete;
1241 +       }
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 *
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? */
1266 +{
1267 +    message_list_ty *ml1;
1268 +    message_list_ty *ml2;
1269 +    message_list_ty *result;
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 +
1282 +    result = message_list_alloc();
1283 +    
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 */
1301 +           message_list_append (result, newmsg);
1302 +           newmsg->used = 1;
1303 +           ++added;
1304 +           continue;
1305 +       }       
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]);
1312 +       
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]);
1316 +       
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 +           }
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 +
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 */
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 +    
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 +           
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 +
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 */
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 +{    
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 ("");
1948 +       if (mp == NULL)
1949 +           return NULL;
1950 +       
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);
1976 +       return mp;
1977 +}
This page took 0.169183 seconds and 3 git commands to generate.