]> git.pld-linux.org Git - packages/gettext.git/commitdiff
- patch based on hacks patch from RH.
authorkloczek <kloczek@pld-linux.org>
Thu, 2 Dec 1999 14:42:46 +0000 (14:42 +0000)
committercvs2git <feedback@pld-linux.org>
Sun, 24 Jun 2012 12:13:13 +0000 (12:13 +0000)
Changed files:
    gettext-hacks.patch -> 1.1

gettext-hacks.patch [new file with mode: 0644]

diff --git a/gettext-hacks.patch b/gettext-hacks.patch
new file mode 100644 (file)
index 0000000..b9e0b98
--- /dev/null
@@ -0,0 +1,1813 @@
+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
+--- gettext.initial/Makefile.am        Mon Feb 22 13:40:47 1999
++++ gettext.hacked/Makefile.am Mon Feb 22 14:10:19 1999
+@@ -19,7 +19,7 @@
+ AUTOMAKE_OPTIONS = 1.3 gnits
+ MAINT_CHARSET = latin1
+-ACLOCAL_AMFLAGS = -I m4
++ACLOCAL_AMFLAGS = --acdir=m4 --acdir=$(shell aclocal --print-ac-dir)
+ gettextsrcdir = $(datadir)/gettext
+ gettextsrc_DATA = ABOUT-NLS
+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
+--- gettext.initial/configure.in       Mon Feb 22 13:40:47 1999
++++ gettext.hacked/configure.in        Mon Feb 22 14:10:20 1999
+@@ -12,7 +12,7 @@
+ AM_PROG_LIBTOOL
+ AC_PROG_CC
+ AC_ISC_POSIX
+-AM_PROG_INSTALL
++AC_PROG_INSTALL
+ AC_PROG_YACC
+ dnl Checks for libraries.
+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
+--- gettext.initial/doc/stamp-vti      Mon Feb 22 13:40:47 1999
++++ gettext.hacked/doc/stamp-vti       Mon Apr 19 18:54:47 1999
+@@ -1,3 +1,3 @@
+-@set UPDATED 30 April 1998
++@set UPDATED 21 March 1999
+ @set EDITION 0.10.35
+ @set VERSION 0.10.35
+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
+--- gettext.initial/doc/version.texi   Mon Feb 22 13:40:47 1999
++++ gettext.hacked/doc/version.texi    Mon Apr 19 18:54:47 1999
+@@ -1,3 +1,3 @@
+-@set UPDATED 30 April 1998
++@set UPDATED 21 March 1999
+ @set EDITION 0.10.35
+ @set VERSION 0.10.35
+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
+--- gettext.initial/src/Makefile.am    Mon Feb 22 13:40:48 1999
++++ gettext.hacked/src/Makefile.am     Mon Feb 22 18:43:39 1999
+@@ -19,7 +19,7 @@
+ AUTOMAKE_OPTIONS = 1.2 gnits
+-bin_PROGRAMS = gettext msgcmp msgfmt msgmerge msgunfmt xgettext msgcomm
++bin_PROGRAMS = gettext msgcmp msgfmt msgmerge msgunfmt xgettext msgcomm msghack
+ noinst_HEADERS = domain.h message.h po-gram.h po-hash.h po-lex.h po.h \
+ str-list.h xget-lex.h po-gram.gen.h po-hash.gen.h dir-list.h
+@@ -52,7 +52,8 @@
+ po.c str-list.c xget-lex.c xgettext.c dir-list.c
+ msgcomm_SOURCES = msgcomm.c message.c po-gram.gen.c po-hash.gen.c po-lex.c \
+ open-po.c po.c str-list.c dir-list.c
+-
++msghack_SOURCES = msghack.c open-po.c dir-list.c message.c str-list.c \
++po-gram.gen.c po-hash.gen.c po-lex.c po.c
+ MAINTAINERCLEANFILES = po-gram.gen.c po-gram.gen.h po-hash.gen.c po-hash.gen.h
+ # Some rules for yacc handling.
+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
+--- gettext.initial/src/message.c      Mon Feb 22 13:40:48 1999
++++ gettext.hacked/src/message.c       Mon Apr 19 05:21:23 1999
+@@ -68,6 +68,9 @@
+ static void message_print PARAMS ((const message_ty *__mp, FILE *__fp,
+                                  const char *__domain, int blank_line,
+                                  int __debug));
++static void master_message_print PARAMS ((const message_ty *__mp,
++                                        FILE *__fp,
++                                        int blank_line));
+ static void message_print_obsolete PARAMS ((const message_ty *__mp, FILE *__fp,
+                                           const char *__domain,
+                                           int blank_line));
+@@ -990,6 +993,156 @@
+ static void
++master_message_print (mp, fp, blank_line)
++     const message_ty *mp;
++     FILE *fp;
++     int blank_line;
++{
++    size_t j;
++
++    /* Separate messages with a blank line.  Uniforum doesn't like blank
++       lines, so use an empty comment (unless there already is one).  */
++    if (blank_line && (!uniforum
++                     || mp->comment == NULL
++                     || mp->comment->nitems == 0
++                     || mp->comment->item[0][0] != '\0'))
++      print_blank_line (fp);
++
++    if (mp->comment != NULL)
++      for (j = 0; j < mp->comment->nitems; ++j) {
++          const unsigned char *s = mp->comment->item[j];
++          do {
++              const unsigned char *e;
++              putc ('#', fp);
++              /* FIXME This is the wrong locale.  While
++                 message_list_print set the "C" locale for LC_CTYPE,
++                 the need to use the correct locale for the file's
++                 contents.  */
++              if (*s != '\0' && !isspace (*s))
++                  putc (' ', fp);
++              e = strchr (s, '\n');
++              if (e == NULL) {
++                  fputs (s, fp);
++                  s = NULL;
++              } else {
++                  fwrite (s, 1, e - s, fp);
++                  s = e + 1;
++              }
++              putc ('\n', fp);
++          } while (s != NULL);
++      }
++
++    if (mp->comment_dot != NULL)
++      for (j = 0; j < mp->comment_dot->nitems; ++j) {
++          const unsigned char *s = mp->comment_dot->item[j];
++          putc ('#', fp);
++          putc ('.', fp);
++          /* FIXME This is the wrong locale.  While
++             message_list_print set the "C" locale for LC_CTYPE, the
++             need to use the correct locale for the file's contents.  */
++          if (*s && !isspace (*s))
++              putc (' ', fp);
++          fputs (s, fp);
++          putc ('\n', fp);
++      }
++
++
++    /* Print the file position comments for every domain.  This will
++       help a human who is trying to navigate the sources.  There is no
++       problem of getting repeat positions, because duplicates are
++       checked for.  */
++    if (mp->filepos_count != 0) {
++      if (uniforum)
++          for (j = 0; j < mp->filepos_count; ++j) {
++              lex_pos_ty *pp = &mp->filepos[j];
++              char *cp = pp->file_name;
++              while (cp[0] == '.' && cp[1] == '/')
++                  cp += 2;
++              /* There are two Sun formats to choose from: SunOS and
++                 Solaris.  Use the Solaris form here.  */
++              fprintf (fp, "# File: %s, line: %ld\n",
++                       cp, (long) pp->line_number);
++          } else {
++              size_t column;
++
++              fputs ("#:", fp);
++              column = 2;
++              for (j = 0; j < mp->filepos_count; ++j) {
++                  lex_pos_ty *pp;
++                  char buffer[20];
++                  char *cp;
++                  size_t len;
++
++                  pp = &mp->filepos[j];
++                  cp = pp->file_name;
++                  while (cp[0] == '.' && cp[1] == '/')
++                      cp += 2;
++                  sprintf (buffer, "%ld", (long) pp->line_number);
++                  len = strlen (cp) + strlen (buffer) + 2;
++                  if (column > 2 && column + len >= page_width)
++                      {
++                          fputs ("\n#:", fp);
++                          column = 2;
++                      }
++                  fprintf (fp, " %s:%s", cp, buffer);
++                  column += len;
++              }
++              putc ('\n', fp);
++          }
++    }
++
++    /* Print flag information in special comment.  */
++    if (mp->is_fuzzy || significant_c_format_p (mp->is_c_format) || mp->do_wrap == no) {
++      int first_flag = 1;
++
++      putc ('#', fp);
++      putc (',', fp);
++
++      /* We don't print the fuzzy flag if the msgstr is empty.  This
++         might be introduced by the user but we want to normalize the
++         output.  */
++      if (mp->is_fuzzy) {
++          fputs (" fuzzy", fp);
++          first_flag = 0;
++      }
++
++      if (significant_c_format_p (mp->is_c_format)) {
++          if (!first_flag)
++              putc (',', fp);
++
++          fputs (make_c_format_description_string (mp->is_c_format, 0),
++                 fp);
++          first_flag = 0;
++      }
++
++      if (mp->do_wrap == no) {
++          if (!first_flag)
++              putc (',', fp);
++
++          fputs (make_c_width_description_string (mp->do_wrap), fp);
++          first_flag = 0;
++      }
++
++      putc ('\n', fp);
++    }
++
++    /* Print each of the message components.  Wrap them nicely so they
++       are as readable as possible.  If there is no recorded msgstr for
++       this domain, emit an empty string.  */
++    wrap (fp, NULL, "msgid", mp->msgid, mp->do_wrap);
++    for (j = 0; j < mp->variant_count; ++j) {
++      char *msgstr;
++
++      msgstr = malloc(strlen(mp->variant[j].domain) + 10);
++      sprintf(msgstr, "msgstr(%s)", mp->variant[j].domain);
++              
++      wrap (fp, NULL, msgstr, mp->variant[j].msgstr, mp->do_wrap);
++    }
++  
++}
++
++
++static void
+ message_print_obsolete (mp, fp, domain, blank_line)
+      const message_ty *mp;
+      FILE *fp;
+@@ -1402,3 +1555,83 @@
+   page_width = n;
+ }
++
++
++/*
++ * HACKS... This prints a mesage list, but it uses the
++ * msgstr(somain) syntax instead
++ */
++ void
++master_list_print (mlp, filename)
++     message_list_ty *mlp;
++     const char *filename;
++{
++    FILE *fp;
++    size_t j;
++    int blank_line;
++#ifdef HAVE_SETLOCALE
++    char *old_locale;
++#endif
++
++    /* We will not write anything if we have no message or only the
++       header entry.  */
++    if (mlp->nitems == 0 || (mlp->nitems == 1 && *mlp->item[0]->msgid == '\0'))
++      return;
++
++    /* Open the output file.  */
++    if (filename != NULL && strcmp (filename, "-") != 0
++      && strcmp (filename, "/dev/stdout") != 0) {
++      fp = fopen (filename, "w");
++      if (fp == NULL)
++          error (EXIT_FAILURE, errno, _("cannot create output file \"%s\""),
++                 filename);
++    } else {
++      fp = stdout;
++      /* xgettext:no-c-format */
++      filename = _("standard output");
++    }
++
++#ifdef HAVE_SETLOCALE
++    /* FIXME This is the wrong locale.  The program is currently set for
++       the user's native language locale, for the error messages.  This
++       code sets it to the "C" locale, but that isn't right either.  The
++       need is to use the correct locale for the file's contents.  */
++    old_locale = setlocale (LC_CTYPE, "C");
++    if (old_locale)
++      old_locale = xstrdup (old_locale);
++#endif
++
++    /* Write out each of the messages for this domain.  */
++    for (j = 0; j < mlp->nitems; ++j)
++      if (mlp->item[j]->obsolete == 0) {
++          master_message_print (mlp->item[j], fp, blank_line);
++          blank_line = 1;
++      }
++
++#if 0 /* screw the obsoletes */
++    /* Write out each of the obsolete messages for this domain.  */
++    for (j = 0; j < mlp->nitems; ++j)
++      if (mlp->item[j]->obsolete != 0) {
++          message_print_obsolete (mlp->item[j], fp, dl->item[k], blank_line);
++          blank_line = 1;
++      }
++#endif
++
++    /* Restore the old locale.  Do this before emitting error messages,
++       so that the correct locale is used for the error.  (Ideally,
++       error should ensure this before calling gettext for the format
++       string.)  */
++#ifdef HAVE_SETLOCALE
++    if (old_locale) {
++      setlocale (LC_CTYPE, old_locale);
++      free (old_locale);
++    }
++#endif
++
++    /* Make sure nothing went wrong.  */
++    if (fflush (fp))
++      error (EXIT_FAILURE, errno, _("error while writing \"%s\" file"),
++             filename);
++    fclose (fp);
++}
++
+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
+--- gettext.initial/src/message.h      Mon Feb 22 13:40:48 1999
++++ gettext.hacked/src/message.h       Mon Apr 19 05:21:23 1999
+@@ -126,4 +126,7 @@
+ int possible_c_format_p PARAMS ((enum is_c_format));
+ void message_page_width_set PARAMS ((size_t width));
++/* Hacks go at the end */
++void master_list_print PARAMS ((message_list_ty *__mlp, const char *__filename));
++
+ #endif /* message.h */
+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
+--- gettext.initial/src/msghack.c      Wed Dec 31 19:00:00 1969
++++ gettext.hacked/src/msghack.c       Wed Oct  6 17:59:54 1999
+@@ -0,0 +1,1482 @@
++/* GNU gettext - internationalization aids
++   Copyright (C) 1995, 1996, 1997, 1998, 1999  Free Software Foundation, Inc.
++   This file was written by Cristian Gafton <gafton@redhat.com>
++
++   This program is free software; you can redistribute it and/or modify
++   it under the terms of the GNU General Public License as published by
++   the Free Software Foundation; either version 2, or (at your option)
++   any later version.
++
++   This program is distributed in the hope that it will be useful,
++   but WITHOUT ANY WARRANTY; without even the implied warranty of
++   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++   GNU General Public License for more details.
++
++   You should have received a copy of the GNU General Public License
++   along with this program; if not, write to the Free Software Foundation,
++   Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
++
++#ifdef HAVE_CONFIG_H
++# include <config.h>
++#endif
++
++#include <getopt.h>
++#include <limits.h>
++#include <stdio.h>
++
++#ifdef STDC_HEADERS
++# include <stdlib.h>
++#endif
++
++#if HAVE_STRING_H
++# include <string.h>
++#else
++# include <strings.h>
++#endif
++
++#if HAVE_LOCALE_H
++# include <locale.h>
++#endif
++
++#include <time.h>
++#include <errno.h>
++
++#include "dir-list.h"
++#include "error.h"
++#include "message.h"
++#include <system.h>
++#include <libintl.h>
++#include "po.h"
++
++#define _(str) gettext (str)
++
++
++/* This structure defines a derived class of the po_ty class.  (See
++   po.h for an explanation.)  */
++typedef struct merge_class_ty merge_class_ty;
++struct merge_class_ty
++{
++  /* inherited instance variables, etc */
++  PO_BASE_TY
++
++  /* Name of domain we are currently examining.  */
++  char *domain;
++
++  /* List of domains already appeared in the current file.  */
++  string_list_ty *domain_list;
++
++  /* List of messages already appeared in the current file.  */
++  message_list_ty *mlp;
++
++  /* Accumulate comments for next message directive */
++  string_list_ty *comment;
++  string_list_ty *comment_dot;
++
++  /* Flags transported in special comments.  */
++  int is_fuzzy;
++  enum is_c_format is_c_format;
++  enum is_c_format do_wrap;
++
++  /* Accumulate filepos comments for the next message directive.  */
++  size_t filepos_count;
++  lex_pos_ty *filepos;
++};
++
++
++/* String containing name the program is called with.  */
++const char *program_name;
++
++/* Verbosity level.  */
++static int verbosity_level;
++
++/* If nonzero, remember comments for file name and line number for each
++   msgid, if present in the reference input.  Defaults to true.  */
++static int line_comment = 1;
++
++/* Force output of PO file even if empty.  */
++static int force_po;
++
++/* should  we merge in the fuzzy messages ? */
++static int fuzzy = 0;
++
++/* Possible split operations */
++#define SPLIT_MSGID   1
++#define SPLIT_MSGSTR  2
++static int split_flag = 0;
++
++/* Possible explode operations */
++#define       EXPLODE_MSGID   4
++#define       EXPLODE_MSGSTR  8
++static int explode_flag = 0;
++
++/* Sort orders */
++#define SORT_BY_FILEPOS               1
++#define SORT_BY_MSGID         2
++static int sort_order = 0;
++
++/* Prototypes for local functions.  */
++static void usage PARAMS ((int __status));
++static void error_print PARAMS ((void));
++static void merge_constructor PARAMS ((po_ty *__that));
++static void merge_destructor PARAMS ((po_ty *__that));
++static void merge_directive_domain PARAMS ((po_ty *__that, char *__name));
++static void merge_directive_message PARAMS ((po_ty *__that, char *__msgid,
++                                           lex_pos_ty *__msgid_pos,
++                                           char *__msgstr, lex_pos_ty *__msgstr_pos));
++static void merge_parse_brief PARAMS ((po_ty *__that));
++static void merge_parse_debrief PARAMS ((po_ty *__that));
++static void merge_comment PARAMS ((po_ty *__that, const char *__s));
++static void merge_comment_dot PARAMS ((po_ty *__that, const char *__s));
++static void merge_comment_special PARAMS ((po_ty *__that, const char *__s));
++static void merge_comment_filepos PARAMS ((po_ty *__that, const char *__name,
++                                         int __line));
++static message_list_ty *grammar PARAMS ((const char *__filename));
++static message_list_ty *append PARAMS ((const char *__fn1, const char *__fn2));
++static message_list_ty *merge PARAMS ((const char *__fn1, const char *__fn2));
++static message_list_ty *invert PARAMS ((const char *__fn));
++static message_list_ty *missing PARAMS ((const char *__fn));
++static message_list_ty *un_duplicate PARAMS ((message_list_ty *dup_list));
++static message_list_ty *empty PARAMS ((const char *__fn));
++static message_list_ty *split PARAMS ((const char *__fn, int __flag));
++static message_list_ty *explode PARAMS ((const char *__fn, int __flag));
++static message_list_ty *master PARAMS ((message_list_ty **prev, const char *__fn,
++                                      const char *__master_id));
++static message_ty *message_join PARAMS ((message_ty *def, message_ty *ref));
++
++/* What kind of actions we can make */
++#define ACTION_DO_SPLIT               1
++#define ACTION_DO_INVERT      2
++#define ACTION_DO_MERGE               3
++#define ACTION_DO_EMPTY               4
++#define ACTION_DO_EXPLODE     5
++#define ACTION_DO_MASTER      6
++#define ACTION_DO_SORT                7
++#define ACTION_DO_APPEND      8
++#define ACTION_DO_UNDUP               9
++#define ACTION_DO_MISSING      10
++
++int main (argc, argv)
++     int argc;
++     char **argv;
++{
++    int opt;
++    int do_action = 0;
++    char *output_file;
++    message_list_ty *result;
++
++    /* Long options.  */
++    const struct option long_options[] =
++    {
++      /* command pairs */
++      { "split-id",  no_argument, &split_flag, SPLIT_MSGID },
++      { "split-str", no_argument, &split_flag, SPLIT_MSGSTR },
++
++      { "explode-id",  required_argument, &explode_flag, EXPLODE_MSGID },
++      { "explode-str", required_argument, &explode_flag, EXPLODE_MSGSTR },
++
++      { "sort-by-file", no_argument, &sort_order, SORT_BY_FILEPOS },
++      { "sort-by-id",   no_argument, &sort_order, SORT_BY_MSGID }, 
++
++      /* flags */
++      { "fuzzy", no_argument, &fuzzy, 1},
++      { "force-po", no_argument, &force_po, 1 },
++      { "width", required_argument, NULL, 'w', },
++      { "output-file", required_argument, NULL, 'o' },
++
++      /* ACTIONS */
++      { "invert",      no_argument, &do_action, ACTION_DO_INVERT },
++      { "merge",       no_argument, &do_action, ACTION_DO_MERGE }, 
++      { "empty",       no_argument, &do_action, ACTION_DO_EMPTY }, 
++      { "master",      no_argument, &do_action, ACTION_DO_MASTER },
++      { "append",      no_argument, &do_action, ACTION_DO_APPEND },
++      { "unduplicate", no_argument, &do_action, ACTION_DO_UNDUP },
++      { "missing",     no_argument, &do_action, ACTION_DO_MISSING },
++
++      /* info */
++      { "help", no_argument, NULL, 'h' },
++      { "version", no_argument, NULL, 'V' },
++
++      { NULL, 0, NULL, 0 }
++    };
++
++
++    /* Set program name for messages.  */
++    program_name = argv[0];
++    verbosity_level = 0;
++    error_print_progname = error_print;
++    gram_max_allowed_errors = INT_MAX;
++
++#ifdef HAVE_SETLOCALE
++    /* Set locale via LC_ALL.  */
++    setlocale (LC_ALL, "");
++#endif
++
++    /* Set the text message domain.  */
++    bindtextdomain (PACKAGE, LOCALEDIR);
++    textdomain (PACKAGE);
++
++    /* Set default values for variables.  */
++    output_file = NULL;
++
++    while ((opt
++          = getopt_long (argc, argv, "ho:Vw:v", long_options, NULL))
++         != EOF)
++      switch (opt) {
++          case '\0':          /* Long option.  */
++              break;
++
++          case 'h':
++              /* Help is requested.  */
++              usage (EXIT_SUCCESS);
++              break;
++
++          case 'o':
++              output_file = optarg;
++              break;
++
++          case 'v':
++              ++verbosity_level;
++              break;
++
++          case 'V':
++              /* Version information is requested.  */
++              printf ("%s (GNU %s) %s\n", basename (program_name), PACKAGE, VERSION);
++              /* xgettext: no-wrap */
++              printf (_("Copyright (C) %s Free Software Foundation, Inc.\n\
++This is free software; see the source for copying conditions.  There is NO\n\
++warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\
++"), "1995, 1996, 1997, 1998");
++              printf (_("Written by %s.\n"), "Cristian Gafton");
++              exit (EXIT_SUCCESS);
++              break;
++
++          case 'w':
++              {
++                  int value;
++                  char *endp;
++                  value = strtol (optarg, &endp, 10);
++                  if (endp != optarg)
++                      message_page_width_set (value);
++              }
++              break;
++
++          default:
++              usage (EXIT_FAILURE);
++              break;
++      }
++
++    /* Test whether we have an .po file name as argument.  */
++    if (optind >= argc) {
++      error (EXIT_SUCCESS, 0, _("no input files given"));
++      usage (EXIT_FAILURE);
++    }
++
++    /* transform one of the pair command into a real action */
++    if (do_action == 0 && split_flag > 0)
++      do_action = ACTION_DO_SPLIT;
++    if (do_action == 0 && explode_flag > 0)
++      do_action = ACTION_DO_EXPLODE;
++    if (do_action == 0 && sort_order != 0)
++      do_action = ACTION_DO_SORT;
++
++    /* okay, we have our file in argv[optind]*/
++    /* what should we do */
++    switch (do_action) {
++      case ACTION_DO_INVERT:
++          /* we are asked to invert the msgid and msgstr strings in a .po file */
++          result = invert (argv[optind]);
++          break;
++      case ACTION_DO_EMPTY:
++          /* we are asked to delete the msgstr text in a .po file */
++          result = empty (argv[optind]);
++          break;
++      case ACTION_DO_SPLIT:
++          /* we are asked to split the file into corresponding meta po files */
++          result = split(argv[optind], split_flag);
++          /* Whatever we are asked to split out */
++          break;
++      case ACTION_DO_EXPLODE:
++          /* we are asked to generate a single meta entry for each xref */
++          result = explode(argv[optind], explode_flag);
++          break;
++      case ACTION_DO_MERGE:
++          /* we gave to merge (id1,str1) and (id2,str2) into (str1,str2) */
++          if (optind + 2 != argc) {
++              error (EXIT_SUCCESS, 0, _("exactly 2 input files required for merge"));
++              usage (EXIT_FAILURE);
++          }      
++          result = merge (argv[optind], argv[optind+1]);
++          break;
++      case ACTION_DO_APPEND:
++          /* append all (id2,str2) entries from second file to the first one
++          * provided that a id2 msgid is not already present there */
++          if (optind + 2 != argc) {
++              error (EXIT_SUCCESS, 0, _("exactly 2 input files required for append"));
++              usage (EXIT_FAILURE);
++          }      
++          result = append (argv[optind], argv[optind+1]);
++          break;
++      case ACTION_DO_UNDUP:
++          /* read in the message catalog and try to colapse
++             the duplicate messageids together */
++          /* Read in the file */
++          result = grammar (argv[optind]);
++          result = un_duplicate(result);
++          break;
++      case ACTION_DO_MASTER:      
++          /* This is a little bit funkier:
++           * Suppose in A.po we have:
++           *  msgid  "id"
++           *  msgstr "str1"
++           * And in B.po we have:
++           *  msgid  "id"
++           *  msgstr "str2"
++           * then the result will look like:
++           *  msgid     "id"
++           *  msgstr(A) "str1"
++           *  msgstr(B) "str2"
++           */
++          result = NULL; /* Start from scratch */
++          for (opt = optind ; opt < argc ; opt++) {
++              char *file_name, *master_id;
++              char *tmp;
++              /* get the file name and the master id */
++              file_name = strdup(argv[opt]);
++              master_id = strdup(basename(argv[opt]));
++              tmp = rindex(master_id, '.');
++              if (tmp == NULL) {
++                  error (EXIT_SUCCESS, 0,
++                         _("Message catalog %s does not have a valid name"), argv[opt]);
++                  usage (EXIT_FAILURE);
++              }                       
++              *tmp = '\0';    
++              result = master(&result, file_name, master_id);
++          }
++          master_list_print(result, output_file);
++          return EXIT_SUCCESS;
++          break;
++      case ACTION_DO_SORT:
++          /* we'll just read in the file and let the sort
++           * statements later deal with it */
++          result = grammar (argv[optind]);
++          break;
++      case ACTION_DO_MISSING:
++          /* generate a new po file of only the missing and non-translated strings */
++          result = missing (argv[optind]);
++          break;
++      default:
++          error (EXIT_SUCCESS, 0, _("Unknown Action"));
++          exit(EXIT_FAILURE);
++    }
++
++    /* Sort the results.  */
++    switch (sort_order) {
++      case SORT_BY_FILEPOS:
++          message_list_sort_by_filepos (result);
++          break;
++      case SORT_BY_MSGID:
++          message_list_sort_by_msgid (result);
++          break;
++    }   
++
++    /* Write the merged message list out.  */
++    message_list_print (result, output_file, force_po, 0);
++
++    exit (EXIT_SUCCESS);
++}
++
++
++/* Display usage information and exit.  */
++static void
++usage (status)
++    int status;
++{
++    if (status != EXIT_SUCCESS)
++      fprintf (stderr, _("Try `%s --help' for more information.\n"),
++               program_name);
++    else {
++      /* xgettext: no-wrap */
++      printf (_("\
++Usage: %s [OPTION] file.po [ref.po]\n\
++Mandatory arguments to long options are mandatory for short options too.\n\
++  -h, --help                  display this help and exit\n\
++      --invert                invert a po file by switching msgid and msgstr\n\
++  -o, --output-file=FILE      result will be written to FILE\n\
++  -v, --verbose               increase verbosity level\n\
++  -V, --version               output version information and exit\n\
++  -w, --width=NUMBER          set output page width\n\
++      --sort-by-file        sort by file in which the msgs appear\n\
++      --sort-by-id          sort by message ids\n\
++      --split-id            split msgid from message catalg into meta catalog\n\
++      --split-str           split msgstr from message catalg into meta catalog\n\
++      --merge               merge file.po and ref.po based on the common msgid\n\
++      --master                      join any number of files in a master-formatted catalog\n\
++      + --fuzzy               use the fuzzy entries when merging in PO files.\n\
++      --empty               empty the contents of the .po file, creating a .pot\n\
++      --append                      append entries from ref.po that don't exist in file.po\n\
++      --explode-id          generate a single meta msgid entry for each xref in file.po\n\
++      --explode-str         generate a single meta msgstr entry for each xref in file.po\n\
++      --unduplicate         colapse together duplicate message ids. (not working currently)\n\
++      --missing                     output only the fuzzy and empty message strings\n\
++\n\
++This program can be used to alter .po files in ways no sane mind would think about.\n\
++Report problems to <gafton@redhat.com>\n\
++"), program_name);
++    }
++    exit (status);
++}
++
++
++/* The address of this function will be assigned to the hook in the
++   error functions.  */
++static void error_print ()
++{
++  /* We don't want the program name to be printed in messages.  Emacs'
++     compile.el does not like this.  */
++
++  /* FIXME Why must this program toady to Emacs?  Why can't compile.el
++     be enhanced to cope with a leading program name?  --PMiller */
++}
++
++
++static void
++merge_constructor (that)
++     po_ty *that;
++{
++  merge_class_ty *this = (merge_class_ty *) that;
++
++  this->mlp = message_list_alloc ();
++  this->domain = MESSAGE_DOMAIN_DEFAULT;
++  this->domain_list = string_list_alloc ();
++  this->comment = NULL;
++  this->comment_dot = NULL;
++  this->filepos_count = 0;
++  this->filepos = NULL;
++  this->is_fuzzy = 0;
++  this->is_c_format = undecided;
++  this->do_wrap = undecided;
++}
++
++
++static void
++merge_destructor (that)
++     po_ty *that;
++{
++  merge_class_ty *this = (merge_class_ty *) that;
++  size_t j;
++
++  string_list_free (this->domain_list);
++  /* Do not free this->mlp.  */
++  if (this->comment != NULL)
++    string_list_free (this->comment);
++  if (this->comment_dot != NULL)
++    string_list_free (this->comment_dot);
++  for (j = 0; j < this->filepos_count; ++j)
++    free (this->filepos[j].file_name);
++  if (this->filepos != NULL)
++    free (this->filepos);
++}
++
++
++static void
++merge_directive_domain (that, name)
++     po_ty *that;
++     char *name;
++{
++  size_t j;
++
++  merge_class_ty *this = (merge_class_ty *) that;
++  /* Override current domain name.  Don't free memory.  */
++  this->domain = name;
++
++  /* If there are accumulated comments, throw them away, they are
++     probably part of the file header, or about the domain directive,
++     and will be unrelated to the next message.  */
++  if (this->comment != NULL)
++    {
++      string_list_free (this->comment);
++      this->comment = NULL;
++    }
++  if (this->comment_dot != NULL)
++    {
++      string_list_free (this->comment_dot);
++      this->comment_dot = NULL;
++    }
++  for (j = 0; j < this->filepos_count; ++j)
++    free (this->filepos[j].file_name);
++  if (this->filepos != NULL)
++    free (this->filepos);
++  this->filepos_count = 0;
++  this->filepos = NULL;
++}
++
++
++static void
++merge_directive_message (that, msgid, msgid_pos, msgstr, msgstr_pos)
++     po_ty *that;
++     char *msgid;
++     lex_pos_ty *msgid_pos;
++     char *msgstr;
++     lex_pos_ty *msgstr_pos;
++{
++  merge_class_ty *this = (merge_class_ty *) that;
++  message_ty *mp;
++  message_variant_ty *mvp;
++  size_t j;
++
++  /* Remember the domain names for later.  */
++  string_list_append_unique (this->domain_list, this->domain);
++
++  /* See if this message ID has been seen before.  */
++  mp = message_list_search (this->mlp, msgid);
++  if (mp)
++    free (msgid);
++  else
++    {
++      mp = message_alloc (msgid);
++      message_list_append (this->mlp, mp);
++    }
++
++  /* Add the accumulated comments to the message.  Clear the
++     accumulation in preparation for the next message.  */
++  if (this->comment != NULL)
++    {
++      for (j = 0; j < this->comment->nitems; ++j)
++      message_comment_append (mp, this->comment->item[j]);
++      string_list_free (this->comment);
++      this->comment = NULL;
++    }
++  if (this->comment_dot != NULL)
++    {
++      for (j = 0; j < this->comment_dot->nitems; ++j)
++      message_comment_dot_append (mp, this->comment_dot->item[j]);
++      string_list_free (this->comment_dot);
++      this->comment_dot = NULL;
++    }
++  for (j = 0; j < this->filepos_count; ++j)
++    {
++      lex_pos_ty *pp;
++
++      pp = &this->filepos[j];
++      message_comment_filepos (mp, pp->file_name, pp->line_number);
++      free (pp->file_name);
++    }
++  mp->is_fuzzy = this->is_fuzzy;
++  mp->is_c_format = this->is_c_format;
++  mp->do_wrap = this->do_wrap;
++
++  if (this->filepos != NULL)
++    free (this->filepos);
++  this->filepos_count = 0;
++  this->filepos = NULL;
++  this->is_fuzzy = 0;
++  this->is_c_format = undecided;
++  this->do_wrap = undecided;
++
++  /* See if this domain has been seen for this message ID.  */
++  mvp = message_variant_search (mp, this->domain);
++  if (mvp)
++    {
++      gram_error_at_line (msgid_pos, _("duplicate message definition"));
++      gram_error_at_line (&mvp->pos, _("\
++...this is the location of the first definition"));
++      free (msgstr);
++    }
++  else
++    message_variant_append (mp, this->domain, msgstr, msgstr_pos);
++}
++
++
++static void
++merge_parse_brief (that)
++     po_ty *that;
++{
++  po_lex_pass_comments (1);
++}
++
++
++static void
++merge_parse_debrief (that)
++     po_ty *that;
++{
++  merge_class_ty *this = (merge_class_ty *) that;
++  message_list_ty *mlp = this->mlp;
++  size_t j;
++
++  /* For each domain in the used-domain-list, make sure each message
++     defines a msgstr in that domain.  */
++  for (j = 0; j < this->domain_list->nitems; ++j)
++    {
++      const char *domain_name;
++      size_t k;
++
++      domain_name = this->domain_list->item[j];
++      for (k = 0; k < mlp->nitems; ++k)
++      {
++        const message_ty *mp;
++        size_t m;
++
++        mp = mlp->item[k];
++        for (m = 0; m < mp->variant_count; ++m)
++          {
++            message_variant_ty *mvp;
++
++            mvp = &mp->variant[m];
++            if (strcmp (domain_name, mvp->domain) == 0)
++              break;
++          }
++        if (m >= mp->variant_count)
++          gram_error_at_line (&mp->variant[0].pos, _("\
++this message has no definition in the \"%s\" domain"), domain_name);
++      }
++    }
++}
++
++
++static void
++merge_comment (that, s)
++     po_ty *that;
++     const char *s;
++{
++  merge_class_ty *this = (merge_class_ty *) that;
++
++  if (this->comment == NULL)
++    this->comment = string_list_alloc ();
++  string_list_append (this->comment, s);
++}
++
++
++static void
++merge_comment_dot (that, s)
++     po_ty *that;
++     const char *s;
++{
++  merge_class_ty *this = (merge_class_ty *) that;
++
++  if (this->comment_dot == NULL)
++    this->comment_dot = string_list_alloc ();
++  string_list_append (this->comment_dot, s);
++}
++
++
++static void
++merge_comment_special (that, s)
++     po_ty *that;
++     const char *s;
++{
++  merge_class_ty *this = (merge_class_ty *) that;
++
++  if (strstr (s, "fuzzy") != NULL)
++    this->is_fuzzy = 1;
++
++  this->is_c_format = parse_c_format_description_string (s);
++  this->do_wrap = parse_c_width_description_string (s);
++}
++
++
++static void
++merge_comment_filepos (that, name, line)
++     po_ty *that;
++     const char *name;
++     int line;
++{
++  merge_class_ty *this = (merge_class_ty *) that;
++  size_t nbytes;
++  lex_pos_ty *pp;
++
++  if (!line_comment)
++    return;
++  nbytes = (this->filepos_count + 1) * sizeof (this->filepos[0]);
++  this->filepos = xrealloc (this->filepos, nbytes);
++  pp = &this->filepos[this->filepos_count++];
++  pp->file_name = xstrdup (name);
++  pp->line_number = line;
++}
++
++
++/* So that the one parser can be used for multiple programs, and also
++   use good data hiding and encapsulation practices, an object
++   oriented approach has been taken.  An object instance is allocated,
++   and all actions resulting from the parse will be through
++   invokations of method functions of that object.  */
++
++static po_method_ty merge_methods =
++{
++  sizeof (merge_class_ty),
++  merge_constructor,
++  merge_destructor,
++  merge_directive_domain,
++  merge_directive_message,
++  merge_parse_brief,
++  merge_parse_debrief,
++  merge_comment,
++  merge_comment_dot,
++  merge_comment_filepos,
++  merge_comment_special
++};
++
++
++static message_list_ty *
++grammar (filename)
++     const char *filename;
++{
++  po_ty *pop;
++  message_list_ty *mlp;
++
++  pop = po_alloc (&merge_methods);
++  po_lex_pass_obsolete_entries (1);
++  po_scan (pop, filename);
++  mlp = ((merge_class_ty *) pop)->mlp;
++  po_free (pop);
++  return mlp;
++}
++
++
++#define DOT_FREQUENCE 10
++
++/*
++ * Given two meta files (m,X) and (m,N) generate a po file (N,X)
++ * preserving the meta information in special comments
++ */
++static message_list_ty *
++merge (fn1, fn2)
++     const char *fn1;                 /* definitions */
++     const char *fn2;                 /* references */
++{
++    message_list_ty *def;
++    message_list_ty *ref;
++    message_ty *defmsg;
++    size_t j, k;
++    size_t merged, fuzzied, missing, obsolete;
++    message_list_ty *result;
++
++    /* This is the definitions file, created by a human.  */
++    def = grammar (fn1);
++
++    /* This is the references file, created by groping the sources with
++     * the xgettext program. */
++    ref = grammar (fn2);
++
++    result = message_list_alloc ();
++
++    /* Every reference must be matched with its definition. */
++    for (j = 0; j < ref->nitems; ++j) {
++      message_ty *refmsg;
++
++      /* Because merging can take a while we print something to signal
++       * we are not dead. */
++      if (verbosity_level >= 1 && j % DOT_FREQUENCE == 0)
++          fputc ('.', stderr);
++
++      refmsg = ref->item[j];
++
++      /* See if it is in the other file.  */
++      defmsg = message_list_search (def, refmsg->msgid);
++      if (defmsg) {
++          /* Merge the reference with the definition: take the #. and
++             #: comments from the reference, take the # comments from
++             the definition, take the msgstr from the definition.  Add
++             this merged entry to the output message list.  */
++          message_ty *mp = message_join (defmsg, refmsg);
++
++          message_list_append (result, mp);
++
++          /* Remember that this message has been used, when we scan
++             later to see if anything was omitted.  */
++          defmsg->used = 1;
++          ++merged;
++          continue;
++      } else {
++          message_ty *mp;
++          const char *tmp;
++          if (verbosity_level > 1)
++              gram_error_at_line (&refmsg->variant[0].pos,
++                                  _("this message is used but not defined in %s"),
++                                  fn1);
++
++          /* Insert the blank record */
++          mp = message_copy (refmsg);
++          tmp = mp->msgid;
++          mp->msgid = mp->variant[0].msgstr;
++          mp->variant[0].msgstr = "";
++          message_list_append (result, mp);
++          ++missing;
++      }
++    }
++
++    /* Look for messages in the definition file, which are not present
++       in the reference file, indicating messages which defined but not
++       used in the program.  */
++    for (k = 0; k < def->nitems; ++k) {
++      defmsg = def->item[k];
++      if (defmsg->used)
++          continue;
++
++      /* Remember the old translation although it is not used anymore.
++         But we mark it as obsolete.  */
++      defmsg->obsolete = 1;
++
++      message_list_append (result, defmsg);
++      ++obsolete;
++    }
++
++    /* Report some statistics.  */
++    if (verbosity_level > 0)
++      fprintf (stderr,
++               _("%sRead %d old + %d reference, merged %d, fuzzied %d, missing %d, obsolete %d.\n"),
++               verbosity_level >= 1 ? "\n" : "",
++               def->nitems, ref->nitems, merged, fuzzied, missing, obsolete);
++    else if (verbosity_level > 0)
++      fputs (_(" done.\n"), stderr);
++
++    /* get rid of the duplicate message ids */
++    return un_duplicate(result);
++}
++
++/*
++ * Given two meta files f1 and f2 append to f1 the entries from f2 that
++ * are not found in f1. First f1 is read in, the for each entry in f2 we
++ * try to locate it in f1; if it is not there already we add it.
++ */
++static message_list_ty *
++append (fn1, fn2)
++     const char *fn1;                 /* base file */
++     const char *fn2;                 /* more stuff found in here */
++{
++    message_list_ty *ml1;
++    message_list_ty *ml2;
++    size_t j;
++    size_t added = 0;
++    int initial;
++      
++    /* This is the definitions file, created by a human.  */
++    ml1 = grammar (fn1);
++    initial = ml1->nitems;
++    
++    /* This is the references file, created by groping the sources with
++     * the xgettext program. */
++    ml2 = grammar (fn2);
++
++    /* Every reference must be matched with its definition. */
++    for (j = 0; j < ml2->nitems; ++j) {
++      message_ty *oldmsg;
++      message_ty *newmsg;
++      int i;
++      
++      /* Because merging can take a while we print something to signal
++       * we are not dead. */
++      if (verbosity_level >= 1 && j % DOT_FREQUENCE == 0)
++          fputc ('.', stderr);
++
++      /* this is the message we want to add */
++      newmsg = ml2->item[j];
++
++      /* See if it is in the other file.  */
++      oldmsg = message_list_search (ml1, newmsg->msgid);
++      if (oldmsg == NULL) { /* not found, stick it in */
++          message_list_append (ml1, newmsg);
++          newmsg->used = 1;
++          ++added;
++          continue;
++      }       
++      /* else, if it is found, add the coments from it */
++      if (newmsg->comment)
++          for (i = 0; i < newmsg->comment->nitems; ++i)
++              message_comment_append (oldmsg, newmsg->comment->item[i]);
++      
++      if (newmsg->comment_dot)
++          for (i = 0; i < newmsg->comment_dot->nitems; ++i)
++              message_comment_dot_append (oldmsg, newmsg->comment_dot->item[i]);
++      
++      /* file position comments */
++      for (i = 0; i < newmsg->filepos_count; ++i) {
++          lex_pos_ty *pp = &newmsg->filepos[i];
++          message_comment_filepos (oldmsg, pp->file_name, pp->line_number);
++      }
++      newmsg->used++;
++    }
++
++    /* Report some statistics.  */
++    if (verbosity_level > 0)
++      fprintf (stderr,
++               _("%sRead %d file1 + %d file2, added %d\n"),
++               verbosity_level >= 1 ? "\n" : "",
++               initial, ml2->nitems, added);
++    else if (verbosity_level > 0)
++      fputs (_(" done.\n"), stderr);
++
++    /* get rid of the duplicate message ids */
++    return ml1;
++}
++
++static message_list_ty *
++master (prev, fn, master_id)
++    message_list_ty **prev;   /* The result of what we had before */
++    const char *fn;           /* file name */
++    const char *master_id;    /* what to put as msgstr(master_id) */
++{
++    message_list_ty *list;
++    message_list_ty *result;
++    int j;
++    
++    /* Read in the file */
++    list = grammar (fn);
++
++    if (*prev == NULL)
++      *prev = message_list_alloc ();
++
++    result = *prev; /* Work with that */
++    
++    /* Every reference must be matched with its definition. */
++    for (j = 0; j < list->nitems; ++j) {
++      message_ty *crtmsg, *merge_msg;
++      
++      /* check for  empty message ids == headers */
++      if (list->item[j]->msgid[0] == '\0') {
++          continue;
++      }
++      
++      if ((list->item[j])->is_fuzzy && (fuzzy == 0)) {
++          /* we don't want fuzzies */
++          continue;
++      }
++      
++      crtmsg = message_copy (list->item[j]);
++
++      /* First, search its pair in the result list ... */
++      merge_msg = message_list_search (result, crtmsg->msgid);
++
++      /* Now here is something broken: we get only the msgstr
++       * from the variant[0] and override its domain with our master_id
++       */
++      crtmsg->variant_count = 1;
++      crtmsg->variant[0].domain = master_id;
++      
++      if (merge_msg != NULL) {
++          int variants;
++          void *temp;
++          
++          /* Ah! we have to do a nasty merge */   
++          variants = ++merge_msg->variant_count;
++          temp = realloc (merge_msg->variant, variants * sizeof(crtmsg->variant[0]));
++          if (temp != NULL) {
++              merge_msg->variant = temp;
++          } else {
++              error (EXIT_FAILURE, 0, "OUT of memory in %s", __FUNCTION__);
++              exit(-1);
++          }
++          merge_msg->variant[variants-1] = crtmsg->variant[0];
++          /* that should be it */
++      } else {
++          /* this is really simple - just add it */
++          message_list_append (result, crtmsg);
++      }
++
++      /* Remember that this message has been used, when we scan
++         later to see if anything was omitted.  */
++      crtmsg->used = 1;
++    }
++
++    return result ; 
++}
++
++static message_list_ty *
++invert (fn)
++    const char *fn; /* file name */
++{
++    message_list_ty *list;
++    size_t j;
++    size_t inverted = 0;
++    message_list_ty *result;
++
++    /* Read in the file */
++    list = grammar (fn);
++
++    result = message_list_alloc ();
++
++    /* Every reference must be matched with its definition. */
++    for (j = 0; j < list->nitems; ++j) {
++      message_ty *crtmsg;
++      int k;
++      
++      /* check for  empty message ids == headers */
++      if (list->item[j]->msgid[0] == '\0') {
++          message_list_append (result, list->item[j]);
++          continue;
++      }
++      
++      crtmsg = message_copy (list->item[j]);
++
++      /*
++       * Now invert it. For each domain found in the file we create a record
++       * containing the inverted pair
++       */
++      for (k = 0; k < crtmsg->variant_count; k++) {
++          message_ty *mp;
++          const char *tmp;
++          
++          mp = message_copy(crtmsg);
++          mp->variant_count = 1;
++          tmp = mp->msgid;    
++          mp->msgid = crtmsg->variant[k].msgstr;
++          mp->variant[0] = crtmsg->variant[k];
++          mp->variant[0].msgstr = tmp;
++          message_list_append (result, mp);
++          ++inverted;
++      }
++
++      /* Remember that this message has been used, when we scan
++         later to see if anything was omitted.  */
++      crtmsg->used = 1;
++    }
++
++    /* get rid of the duplicate message ids */
++    return un_duplicate(result);
++}
++
++static message_list_ty *
++missing (fn)
++    const char *fn; /* file name */
++{
++    message_list_ty *list;
++    size_t j;
++    message_list_ty *result;
++
++    /* Read in the file */
++    list = grammar (fn);
++
++    result = message_list_alloc ();
++
++    /* Every reference must be matched with its definition. */
++    for (j = 0; j < list->nitems; ++j) {
++      int k;
++      
++      /* check for  empty message ids == headers */
++      if (list->item[j]->msgid[0] == '\0') {
++          message_list_append (result, list->item[j]);
++          continue;
++      }
++      
++      /* Fuzzies go in */
++      if (list->item[j]->is_fuzzy) {
++          message_list_append (result, list->item[j]);
++          continue;
++      }
++
++      /* Check for empty translations */
++      for (k = 0; k < list->item[j]->variant_count; k++) {
++          if (strlen(list->item[j]->variant[k].msgstr) <= 1) {
++              message_list_append (result, list->item[j]);
++              break;
++          }
++      }
++
++      /* Remember that this message has been used, when we scan
++         later to see if anything was omitted.  */
++      list->item[j]->used = 1;
++    }
++    return result;
++}
++
++static message_list_ty *
++un_duplicate (dup_list)
++    message_list_ty *dup_list; /* list containing duplicates */
++{
++    message_list_ty *result;
++    size_t j;    
++
++    result = message_list_alloc ();
++     
++    /* First iteration, clear the used flag */
++    for (j = 0; j < dup_list->nitems; ++j)
++      dup_list->item[j]->used = 0;
++    
++    /* This is a cheesy O(n^2) dupe elimination "algorithm"
++     * One day I will replace it by a quicksort() followed by
++     * a walk through the whole list one more time and that will bring
++     * it down to O(n log(n)) */
++    for (j = 0; j < dup_list->nitems; ++j) {
++      message_ty *crtmsg;
++      size_t k;
++              
++      /* get the current message */
++      crtmsg = dup_list->item[j];
++
++      if (crtmsg->used > 0)
++          continue;
++      
++      for (k = j + 1; k < dup_list->nitems; ++k) {
++          message_ty *newmsg;
++          size_t i;
++          
++          newmsg = dup_list->item[k];
++      
++          if (strcmp(crtmsg->msgid, newmsg->msgid) != 0 ||
++              newmsg->used > 0)
++              continue;
++          
++          if (newmsg->comment)
++              for (i = 0; i < newmsg->comment->nitems; ++i)
++                  message_comment_append (crtmsg, newmsg->comment->item[i]);
++          
++          if (newmsg->comment_dot)
++              for (i = 0; i < newmsg->comment_dot->nitems; ++i)
++                  message_comment_dot_append (crtmsg, newmsg->comment_dot->item[i]);
++
++          /* file position comments */
++          for (i = 0; i < newmsg->filepos_count; ++i) {
++              lex_pos_ty *pp = &newmsg->filepos[i];
++              message_comment_filepos (crtmsg, pp->file_name, pp->line_number);
++          }
++      
++          fprintf(stderr, "%05d : %05d\r", j, k);
++          /* Now mark it as used */    
++          newmsg->used++;
++      }
++
++      /* Now put the resulting entry on the final list */
++      message_list_append (result, crtmsg);
++    }
++    
++    return result;
++    
++}
++      
++message_ty *
++message_join (def, ref)
++    message_ty *def;
++    message_ty *ref;
++{
++    message_ty *result;
++    size_t j;
++    char *meta_comment;
++    
++    /* is this the header ? */
++    if (ref->msgid[0] == '\0') {
++      result = message_copy(ref);
++      return result;
++    };
++    
++
++    /* XXX: FIX ME!!!
++     * We are not processing in any way the variant list at this time.
++     * We assume blindly that joining two pairs onn variant[0] will yield
++     * the correct result
++     */
++
++    /* here it goes: (m,X) join m(m,N) = (N,X) */
++    result = message_copy(def);
++    /* here we should be looping over all domains */
++    result->msgid = ref->variant[0].msgstr;
++    
++    /* Take the comments from the definition file.  There will be none at
++     * all in the reference file, as it was generated by xgettext.
++     */
++    /* we don't do that here because result is already initialized from def
++       --cristiang */
++    /*if (def->comment) */
++    /*        for (j = 0; j < def->comment->nitems; ++j) */
++    /*            message_comment_append (result, def->comment->item[j]); */
++
++    /* now add the meta information for the common join field */
++    j = strlen(ref->msgid) + 10;
++    meta_comment = alloca(j);
++    if (meta_comment != NULL) {
++      snprintf(meta_comment, j-1, "meta=%s", ref->msgid); /* should be safe */
++      message_comment_append(result, meta_comment);
++    } else {
++      message_comment_append(result, "meta=ERROR!!!");
++      message_comment_append(result, ref->msgid);
++    }
++    
++    /* Take the dot comments from the reference file, as they are
++       generated by xgettext.  Any in the definition file are old ones
++       collected by previous runs of xgettext and msgmerge.  */
++    if (ref->comment_dot)
++      for (j = 0; j < ref->comment_dot->nitems; ++j)
++          message_comment_dot_append (result, ref->comment_dot->item[j]);
++
++/*     message_comment_dot_append(result, "this is my test"); */
++    /* The flags are mixed in a special way.  Some informations come
++       from the reference message (such as format/no-format), others
++       come from the definition file (fuzzy or not).  */
++    result->is_fuzzy = def->is_fuzzy;
++    result->is_c_format = ref->is_c_format;
++    result->do_wrap = ref->do_wrap;
++
++    /* Take the file position comments from the reference file, as they
++       are generated by xgettext.  Any in the definition file are old ones
++       collected by previous runs of xgettext and msgmerge.  */
++    for (j = 0; j < ref->filepos_count; ++j) {
++      lex_pos_ty *pp = &ref->filepos[j];
++      message_comment_filepos (result, pp->file_name, pp->line_number);
++    }
++
++    /* All done, return the merged message to the caller.  */
++    return result;
++}
++
++static message_list_ty *
++split (fn, flag)
++    const char *fn; /* file name */
++    int flag;             /* what should we be splitting out */
++{
++    message_list_ty *list;
++    size_t j;
++    message_list_ty *result;
++
++    /* Read in the file */
++    list = grammar (fn);
++
++    result = message_list_alloc ();
++
++    /* Every reference must be matched with its definition. */
++    for (j = 0; j < list->nitems; ++j) {
++      message_ty *crtmsg;
++      
++      /* get the current message */
++      crtmsg = message_copy (list->item[j]);
++
++      /* search all comments looking for our meta= */
++      if (crtmsg->comment) {
++          int k;
++          for (k = 0; k < crtmsg->comment->nitems; ++k) {
++              char *tmp;
++
++              tmp = strstr(crtmsg->comment->item[k], "meta=");
++              if (tmp != NULL) { /* found it */
++                  message_ty *res;
++                  int i;
++                  message_variant_ty *mvp = NULL;
++
++                  res = message_alloc(xstrdup(tmp+5));
++                  res->variant_count = 1;
++                  mvp = malloc(sizeof(struct message_variant_ty));
++                  if (mvp == NULL) {
++                      error (EXIT_FAILURE, 0, _("Weird out of memory situation"));
++                      usage (EXIT_FAILURE);
++                  }
++                  *mvp = crtmsg->variant[0];
++                  res->variant = mvp;
++                  switch(flag) {
++                      case SPLIT_MSGID:
++                          res->variant[0].msgstr = crtmsg->msgid;
++                          /* transport over all the dot  comments */
++                          if (crtmsg->comment_dot)
++                              for (i = 0; i < crtmsg->comment_dot->nitems; ++i)
++                                  message_comment_dot_append(res, crtmsg->comment_dot->item[i]);
++                          break;
++                      case SPLIT_MSGSTR:
++                          res->variant[0].msgstr = crtmsg->variant[0].msgstr;
++                          /* transport over the comments with the exception of
++                             the dot comments and the meta= one */
++                          for (i = 0; i < crtmsg->comment->nitems; ++i)
++                              if (i != k)
++                                  message_comment_append(res, crtmsg->comment->item[i]);
++                          break;
++                      default:
++                          error (EXIT_SUCCESS, 0, _("Unknwon split mode"));
++                          usage (EXIT_FAILURE);
++                  }
++                  message_list_append (result, res);
++              }
++          }
++      } else {
++          /* we have no meta comment on this one */
++          continue;
++      }
++    } 
++    return result;
++}
++
++static message_list_ty *
++explode (fn, flag)
++    const char *fn; /* file name */
++    int flag;             /* what should we be splitting out */
++{
++    message_list_ty *list;
++    size_t j;
++    message_list_ty *result;
++
++    /* Read in the file */
++    list = grammar (fn);
++
++    result = message_list_alloc ();
++
++    /* Every reference ... */
++    for (j = 0; j < list->nitems; ++j) {
++      message_ty *crtmsg;
++      int k;
++      
++      /* Get the current message */
++      crtmsg = message_copy (list->item[j]);
++
++      /* Every "conformant" cross reference ... */
++      for (k = 0; k < crtmsg->filepos_count; ++k) {
++          lex_pos_ty *pp;
++          char buf[1024];
++          const char *fn, *tn;
++          const char *f, *fe;
++          int ln;
++          message_ty *res;
++          int i;
++          message_variant_ty *mvp = NULL;
++
++          pp = &crtmsg->filepos[k];
++          fn = pp->file_name;
++          ln = pp->line_number;
++
++          switch(ln) {
++              default:
++                  tn = NULL;
++                  break;
++              case 1004:
++                  tn = "(Summary)";
++                  break;
++              case 1005:
++                  tn = "(Description)";
++                  break;
++              case 1016:
++                  tn = "(Group)";
++                  break;
++          }
++
++          /* ... weird tags we do not want */
++          if (tn == NULL)
++              continue;
++
++          /* Find the text after the name-version-release */
++          if ((f = strrchr(fn, '-')) == NULL ||
++              (fe = strchr(f, '.')) == NULL) {
++              fprintf(stderr, _("skipping malformed xref \"%s\"\n"), fn);
++              continue;
++          }
++          fe = fn + strlen(fn) - sizeof(".src.rpm") + 1;
++
++          /* ... src.rpm's we do not want */
++          if ( !strcmp(fe, ".src.rpm") )
++              continue;
++
++          /* Position at end of name */
++          fe = strrchr(fn, '-') - 1;
++          while (fe > fn && *fe != '-')
++              --fe;
++
++          /* Construct meta tag */
++          strncpy(buf, fn, (fe-fn) );
++          buf[fe-fn] = '\0';
++          strncat(buf, tn, (sizeof(buf) - strlen(buf)) );
++
++          res = message_alloc(xstrdup(buf));
++          res->variant_count = 1;
++          mvp = malloc(sizeof(struct message_variant_ty));
++          if (mvp == NULL) {
++              error (EXIT_FAILURE, 0, _("Weird out of memory situation"));
++              usage (EXIT_FAILURE);
++          }
++          *mvp = crtmsg->variant[0];
++          res->variant = mvp;
++          switch(flag) {
++              case EXPLODE_MSGID:
++                  res->variant[0].msgstr = crtmsg->msgid;
++                  /* transport over all the dot  comments */
++                  if (crtmsg->comment_dot)
++                      for (i = 0; i < crtmsg->comment_dot->nitems; ++i)
++                          message_comment_dot_append(res, crtmsg->comment_dot->item[i]);
++                  break;
++              case EXPLODE_MSGSTR:
++                  res->variant[0].msgstr = crtmsg->variant[0].msgstr;
++#if 0
++                  /* transport over the comments with the exception of
++                     the dot comments */
++                  for (i = 0; i < crtmsg->comment->nitems; ++i)
++                      message_comment_append(res, crtmsg->comment->item[i]);
++#endif
++                  break;
++              default:
++                  error (EXIT_SUCCESS, 0, _("Unknwon explode mode"));
++                  usage (EXIT_FAILURE);
++          }
++          message_list_append (result, res);
++      }
++    } 
++    return result;
++}
++
++#define TM_YEAR_ORIGIN 1900
++
++static message_list_ty *
++empty (fn)
++    const char *fn; /* file name */
++{
++    message_list_ty *list;
++    size_t j;
++    int had_header = 0;
++    message_list_ty *result;
++
++    /* Read in the file */
++    list = grammar (fn);
++
++    result = message_list_alloc ();
++
++    /* Every reference must be matched with its definition. */
++    for (j = 0; j < list->nitems; ++j) {
++      if (list->item[j]->msgid[0] == '\0') {
++          had_header++;
++          break;
++      }
++    }
++
++    /* If we don't have a header, we should try to add one */
++    if (!had_header) {
++      time_t now;
++      struct tm local_time;
++      message_ty *mp;
++      char *msgstr;
++      static lex_pos_ty pos = { __FILE__, __LINE__, };
++      
++      mp = message_alloc ("");
++
++      message_comment_append (mp, "\
++SOME DESCRIPTIVE TITLE.\n\
++FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.\n");
++
++      time (&now);
++      local_time = *localtime (&now);
++
++      asprintf (&msgstr, "\
++Project-Id-Version: PACKAGE VERSION\n\
++POT-Creation-Date: %d-%02d-%02d %02d:%02d\n\
++PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n\
++Last-Translator: FULL NAME <EMAIL@ADDRESS>\n\
++Language-Team: LANGUAGE <LL@li.org>\n\
++MIME-Version: 1.0\n\
++Content-Type: text/plain; charset=CHARSET\n\
++Content-Transfer-Encoding: ENCODING\n",
++                local_time.tm_year + TM_YEAR_ORIGIN,
++                local_time.tm_mon + 1,
++                local_time.tm_mday,
++                local_time.tm_hour,
++                local_time.tm_min);
++
++      if (msgstr == NULL)
++          error(EXIT_FAILURE, errno, _("while preparing output"));
++      message_variant_append (mp, MESSAGE_DOMAIN_DEFAULT, msgstr, &pos);
++      message_list_append (result, mp);
++    }
++
++    /* time to add the rest */
++    for (j = 0; j < list->nitems; ++j) {
++      message_ty *crtmsg;
++    
++      crtmsg = list->item[j];
++      if (crtmsg->msgid[0] != '\0') {
++          /* empty the translations */
++          crtmsg->variant_count = 1;
++          crtmsg->variant[0].msgstr = "";
++      }
++      crtmsg->used = 1;
++      message_list_append (result, crtmsg);
++    }
++    return result;
++}
This page took 0.149039 seconds and 4 git commands to generate.