Blame gettext-tools/src/msgl-cat.c

Packit Bot 06c835
/* Message list concatenation and duplicate handling.
Packit Bot 06c835
   Copyright (C) 2001-2003, 2005-2008, 2012, 2015 Free Software
Packit Bot 06c835
   Foundation, Inc.
Packit Bot 06c835
   Written by Bruno Haible <haible@clisp.cons.org>, 2001.
Packit Bot 06c835
Packit Bot 06c835
   This program is free software: you can redistribute it and/or modify
Packit Bot 06c835
   it under the terms of the GNU General Public License as published by
Packit Bot 06c835
   the Free Software Foundation; either version 3 of the License, or
Packit Bot 06c835
   (at your option) any later version.
Packit Bot 06c835
Packit Bot 06c835
   This program is distributed in the hope that it will be useful,
Packit Bot 06c835
   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Bot 06c835
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit Bot 06c835
   GNU General Public License for more details.
Packit Bot 06c835
Packit Bot 06c835
   You should have received a copy of the GNU General Public License
Packit Bot 06c835
   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
Packit Bot 06c835
Packit Bot 06c835
Packit Bot 06c835
#ifdef HAVE_CONFIG_H
Packit Bot 06c835
# include "config.h"
Packit Bot 06c835
#endif
Packit Bot 06c835
#include <alloca.h>
Packit Bot 06c835
Packit Bot 06c835
/* Specification.  */
Packit Bot 06c835
#include "msgl-cat.h"
Packit Bot 06c835
Packit Bot 06c835
#include <limits.h>
Packit Bot 06c835
#include <stdbool.h>
Packit Bot 06c835
#include <stddef.h>
Packit Bot 06c835
#include <stdlib.h>
Packit Bot 06c835
#include <string.h>
Packit Bot 06c835
Packit Bot 06c835
#include "error.h"
Packit Bot 06c835
#include "xerror.h"
Packit Bot 06c835
#include "xvasprintf.h"
Packit Bot 06c835
#include "message.h"
Packit Bot 06c835
#include "read-catalog.h"
Packit Bot 06c835
#include "po-charset.h"
Packit Bot 06c835
#include "msgl-ascii.h"
Packit Bot 06c835
#include "msgl-equal.h"
Packit Bot 06c835
#include "msgl-iconv.h"
Packit Bot 06c835
#include "xalloc.h"
Packit Bot 06c835
#include "xmalloca.h"
Packit Bot 06c835
#include "c-strstr.h"
Packit Bot 06c835
#include "basename.h"
Packit Bot 06c835
#include "gettext.h"
Packit Bot 06c835
Packit Bot 06c835
#define _(str) gettext (str)
Packit Bot 06c835
Packit Bot 06c835
Packit Bot 06c835
/* These variables control which messages are selected.  */
Packit Bot 06c835
int more_than;
Packit Bot 06c835
int less_than;
Packit Bot 06c835
Packit Bot 06c835
/* If true, use the first available translation.
Packit Bot 06c835
   If false, merge all available translations into one and fuzzy it.  */
Packit Bot 06c835
bool use_first;
Packit Bot 06c835
Packit Bot 06c835
/* If true, merge like msgcomm.
Packit Bot 06c835
   If false, merge like msgcat and msguniq.  */
Packit Bot 06c835
bool msgcomm_mode = false;
Packit Bot 06c835
Packit Bot 06c835
/* If true, omit the header entry.
Packit Bot 06c835
   If false, keep the header entry present in the input.  */
Packit Bot 06c835
bool omit_header = false;
Packit Bot 06c835
Packit Bot 06c835
Packit Bot 06c835
static bool
Packit Bot 06c835
is_message_selected (const message_ty *tmp)
Packit Bot 06c835
{
Packit Bot 06c835
  int used = (tmp->used >= 0 ? tmp->used : - tmp->used);
Packit Bot 06c835
Packit Bot 06c835
  return (is_header (tmp)
Packit Bot 06c835
          ? !omit_header        /* keep the header entry */
Packit Bot 06c835
          : (used > more_than && used < less_than));
Packit Bot 06c835
}
Packit Bot 06c835
Packit Bot 06c835
Packit Bot 06c835
static bool
Packit Bot 06c835
is_message_needed (const message_ty *mp)
Packit Bot 06c835
{
Packit Bot 06c835
  if (!msgcomm_mode
Packit Bot 06c835
      && ((!is_header (mp) && mp->is_fuzzy) || mp->msgstr[0] == '\0'))
Packit Bot 06c835
    /* Weak translation.  Needed if there are only weak translations.  */
Packit Bot 06c835
    return mp->tmp->used < 0 && is_message_selected (mp->tmp);
Packit Bot 06c835
  else
Packit Bot 06c835
    /* Good translation.  */
Packit Bot 06c835
    return is_message_selected (mp->tmp);
Packit Bot 06c835
}
Packit Bot 06c835
Packit Bot 06c835
Packit Bot 06c835
/* The use_first logic.  */
Packit Bot 06c835
static bool
Packit Bot 06c835
is_message_first_needed (const message_ty *mp)
Packit Bot 06c835
{
Packit Bot 06c835
  if (mp->tmp->obsolete && is_message_needed (mp))
Packit Bot 06c835
    {
Packit Bot 06c835
      mp->tmp->obsolete = false;
Packit Bot 06c835
      return true;
Packit Bot 06c835
    }
Packit Bot 06c835
  else
Packit Bot 06c835
    return false;
Packit Bot 06c835
}
Packit Bot 06c835
Packit Bot 06c835
Packit Bot 06c835
msgdomain_list_ty *
Packit Bot 06c835
catenate_msgdomain_list (string_list_ty *file_list,
Packit Bot 06c835
                         catalog_input_format_ty input_syntax,
Packit Bot 06c835
                         const char *to_code)
Packit Bot 06c835
{
Packit Bot 06c835
  const char * const *files = file_list->item;
Packit Bot 06c835
  size_t nfiles = file_list->nitems;
Packit Bot 06c835
  msgdomain_list_ty **mdlps;
Packit Bot 06c835
  const char ***canon_charsets;
Packit Bot 06c835
  const char ***identifications;
Packit Bot 06c835
  msgdomain_list_ty *total_mdlp;
Packit Bot 06c835
  const char *canon_to_code;
Packit Bot 06c835
  size_t n, j;
Packit Bot 06c835
Packit Bot 06c835
  /* Read input files.  */
Packit Bot 06c835
  mdlps = XNMALLOC (nfiles, msgdomain_list_ty *);
Packit Bot 06c835
  for (n = 0; n < nfiles; n++)
Packit Bot 06c835
    mdlps[n] = read_catalog_file (files[n], input_syntax);
Packit Bot 06c835
Packit Bot 06c835
  /* Determine the canonical name of each input file's encoding.  */
Packit Bot 06c835
  canon_charsets = XNMALLOC (nfiles, const char **);
Packit Bot 06c835
  for (n = 0; n < nfiles; n++)
Packit Bot 06c835
    {
Packit Bot 06c835
      msgdomain_list_ty *mdlp = mdlps[n];
Packit Bot 06c835
      size_t k;
Packit Bot 06c835
Packit Bot 06c835
      canon_charsets[n] = XNMALLOC (mdlp->nitems, const char *);
Packit Bot 06c835
      for (k = 0; k < mdlp->nitems; k++)
Packit Bot 06c835
        {
Packit Bot 06c835
          message_list_ty *mlp = mdlp->item[k]->messages;
Packit Bot 06c835
          const char *canon_from_code = NULL;
Packit Bot 06c835
Packit Bot 06c835
          if (mlp->nitems > 0)
Packit Bot 06c835
            {
Packit Bot 06c835
              for (j = 0; j < mlp->nitems; j++)
Packit Bot 06c835
                if (is_header (mlp->item[j]) && !mlp->item[j]->obsolete)
Packit Bot 06c835
                  {
Packit Bot 06c835
                    const char *header = mlp->item[j]->msgstr;
Packit Bot 06c835
Packit Bot 06c835
                    if (header != NULL)
Packit Bot 06c835
                      {
Packit Bot 06c835
                        const char *charsetstr = c_strstr (header, "charset=");
Packit Bot 06c835
Packit Bot 06c835
                        if (charsetstr != NULL)
Packit Bot 06c835
                          {
Packit Bot 06c835
                            size_t len;
Packit Bot 06c835
                            char *charset;
Packit Bot 06c835
                            const char *canon_charset;
Packit Bot 06c835
Packit Bot 06c835
                            charsetstr += strlen ("charset=");
Packit Bot 06c835
                            len = strcspn (charsetstr, " \t\n");
Packit Bot 06c835
                            charset = (char *) xmalloca (len + 1);
Packit Bot 06c835
                            memcpy (charset, charsetstr, len);
Packit Bot 06c835
                            charset[len] = '\0';
Packit Bot 06c835
Packit Bot 06c835
                            canon_charset = po_charset_canonicalize (charset);
Packit Bot 06c835
                            if (canon_charset == NULL)
Packit Bot 06c835
                              {
Packit Bot 06c835
                                /* Don't give an error for POT files, because
Packit Bot 06c835
                                   POT files usually contain only ASCII
Packit Bot 06c835
                                   msgids.  */
Packit Bot 06c835
                                const char *filename = files[n];
Packit Bot 06c835
                                size_t filenamelen = strlen (filename);
Packit Bot 06c835
Packit Bot 06c835
                                if (filenamelen >= 4
Packit Bot 06c835
                                    && memcmp (filename + filenamelen - 4,
Packit Bot 06c835
                                               ".pot", 4) == 0
Packit Bot 06c835
                                    && strcmp (charset, "CHARSET") == 0)
Packit Bot 06c835
                                  canon_charset = po_charset_ascii;
Packit Bot 06c835
                                else
Packit Bot 06c835
                                  error (EXIT_FAILURE, 0,
Packit Bot 06c835
                                         _("\
Packit Bot 06c835
present charset \"%s\" is not a portable encoding name"),
Packit Bot 06c835
                                         charset);
Packit Bot 06c835
                              }
Packit Bot 06c835
Packit Bot 06c835
                            freea (charset);
Packit Bot 06c835
Packit Bot 06c835
                            if (canon_from_code == NULL)
Packit Bot 06c835
                              canon_from_code = canon_charset;
Packit Bot 06c835
                            else if (canon_from_code != canon_charset)
Packit Bot 06c835
                              error (EXIT_FAILURE, 0,
Packit Bot 06c835
                                     _("\
Packit Bot 06c835
two different charsets \"%s\" and \"%s\" in input file"),
Packit Bot 06c835
                                     canon_from_code, canon_charset);
Packit Bot 06c835
                          }
Packit Bot 06c835
                      }
Packit Bot 06c835
                  }
Packit Bot 06c835
              if (canon_from_code == NULL)
Packit Bot 06c835
                {
Packit Bot 06c835
                  if (is_ascii_message_list (mlp))
Packit Bot 06c835
                    canon_from_code = po_charset_ascii;
Packit Bot 06c835
                  else if (mdlp->encoding != NULL)
Packit Bot 06c835
                    canon_from_code = mdlp->encoding;
Packit Bot 06c835
                  else
Packit Bot 06c835
                    {
Packit Bot 06c835
                      if (k == 0)
Packit Bot 06c835
                        error (EXIT_FAILURE, 0, _("\
Packit Bot 06c835
input file '%s' doesn't contain a header entry with a charset specification"),
Packit Bot 06c835
                               files[n]);
Packit Bot 06c835
                      else
Packit Bot 06c835
                        error (EXIT_FAILURE, 0, _("\
Packit Bot 06c835
domain \"%s\" in input file '%s' doesn't contain a header entry with a charset specification"),
Packit Bot 06c835
                               mdlp->item[k]->domain, files[n]);
Packit Bot 06c835
                    }
Packit Bot 06c835
                }
Packit Bot 06c835
            }
Packit Bot 06c835
          canon_charsets[n][k] = canon_from_code;
Packit Bot 06c835
        }
Packit Bot 06c835
    }
Packit Bot 06c835
Packit Bot 06c835
  /* Determine textual identifications of each file/domain combination.  */
Packit Bot 06c835
  identifications = XNMALLOC (nfiles, const char **);
Packit Bot 06c835
  for (n = 0; n < nfiles; n++)
Packit Bot 06c835
    {
Packit Bot 06c835
      const char *filename = basename (files[n]);
Packit Bot 06c835
      msgdomain_list_ty *mdlp = mdlps[n];
Packit Bot 06c835
      size_t k;
Packit Bot 06c835
Packit Bot 06c835
      identifications[n] = XNMALLOC (mdlp->nitems, const char *);
Packit Bot 06c835
      for (k = 0; k < mdlp->nitems; k++)
Packit Bot 06c835
        {
Packit Bot 06c835
          const char *domain = mdlp->item[k]->domain;
Packit Bot 06c835
          message_list_ty *mlp = mdlp->item[k]->messages;
Packit Bot 06c835
          char *project_id = NULL;
Packit Bot 06c835
Packit Bot 06c835
          for (j = 0; j < mlp->nitems; j++)
Packit Bot 06c835
            if (is_header (mlp->item[j]) && !mlp->item[j]->obsolete)
Packit Bot 06c835
              {
Packit Bot 06c835
                const char *header = mlp->item[j]->msgstr;
Packit Bot 06c835
Packit Bot 06c835
                if (header != NULL)
Packit Bot 06c835
                  {
Packit Bot 06c835
                    const char *cp = c_strstr (header, "Project-Id-Version:");
Packit Bot 06c835
Packit Bot 06c835
                    if (cp != NULL)
Packit Bot 06c835
                      {
Packit Bot 06c835
                        const char *endp;
Packit Bot 06c835
Packit Bot 06c835
                        cp += sizeof ("Project-Id-Version:") - 1;
Packit Bot 06c835
Packit Bot 06c835
                        endp = strchr (cp, '\n');
Packit Bot 06c835
                        if (endp == NULL)
Packit Bot 06c835
                          endp = cp + strlen (cp);
Packit Bot 06c835
Packit Bot 06c835
                        while (cp < endp && *cp == ' ')
Packit Bot 06c835
                          cp++;
Packit Bot 06c835
Packit Bot 06c835
                        if (cp < endp)
Packit Bot 06c835
                          {
Packit Bot 06c835
                            size_t len = endp - cp;
Packit Bot 06c835
                            project_id = XNMALLOC (len + 1, char);
Packit Bot 06c835
                            memcpy (project_id, cp, len);
Packit Bot 06c835
                            project_id[len] = '\0';
Packit Bot 06c835
                          }
Packit Bot 06c835
                        break;
Packit Bot 06c835
                      }
Packit Bot 06c835
                  }
Packit Bot 06c835
              }
Packit Bot 06c835
Packit Bot 06c835
          identifications[n][k] =
Packit Bot 06c835
            (project_id != NULL
Packit Bot 06c835
             ? (k > 0 ? xasprintf ("%s:%s (%s)", filename, domain, project_id)
Packit Bot 06c835
                      : xasprintf ("%s (%s)", filename, project_id))
Packit Bot 06c835
             : (k > 0 ? xasprintf ("%s:%s", filename, domain)
Packit Bot 06c835
                      : xasprintf ("%s", filename)));
Packit Bot 06c835
        }
Packit Bot 06c835
    }
Packit Bot 06c835
Packit Bot 06c835
  /* Create list of resulting messages, but don't fill it.  Only count
Packit Bot 06c835
     the number of translations for each message.
Packit Bot 06c835
     If for a message, there is at least one non-fuzzy, non-empty translation,
Packit Bot 06c835
     use only the non-fuzzy, non-empty translations.  Otherwise use the
Packit Bot 06c835
     fuzzy or empty translations as well.  */
Packit Bot 06c835
  total_mdlp = msgdomain_list_alloc (true);
Packit Bot 06c835
  for (n = 0; n < nfiles; n++)
Packit Bot 06c835
    {
Packit Bot 06c835
      msgdomain_list_ty *mdlp = mdlps[n];
Packit Bot 06c835
      size_t k;
Packit Bot 06c835
Packit Bot 06c835
      for (k = 0; k < mdlp->nitems; k++)
Packit Bot 06c835
        {
Packit Bot 06c835
          const char *domain = mdlp->item[k]->domain;
Packit Bot 06c835
          message_list_ty *mlp = mdlp->item[k]->messages;
Packit Bot 06c835
          message_list_ty *total_mlp;
Packit Bot 06c835
Packit Bot 06c835
          total_mlp = msgdomain_list_sublist (total_mdlp, domain, true);
Packit Bot 06c835
Packit Bot 06c835
          for (j = 0; j < mlp->nitems; j++)
Packit Bot 06c835
            {
Packit Bot 06c835
              message_ty *mp = mlp->item[j];
Packit Bot 06c835
              message_ty *tmp;
Packit Bot 06c835
              size_t i;
Packit Bot 06c835
Packit Bot 06c835
              tmp = message_list_search (total_mlp, mp->msgctxt, mp->msgid);
Packit Bot 06c835
              if (tmp == NULL)
Packit Bot 06c835
                {
Packit Bot 06c835
                  tmp = message_alloc (mp->msgctxt, mp->msgid, mp->msgid_plural,
Packit Bot 06c835
                                       NULL, 0, &mp->pos);
Packit Bot 06c835
                  tmp->is_fuzzy = true; /* may be set to false later */
Packit Bot 06c835
                  for (i = 0; i < NFORMATS; i++)
Packit Bot 06c835
                    tmp->is_format[i] = undecided; /* may be set to yes/no later */
Packit Bot 06c835
                  tmp->range.min = - INT_MAX;
Packit Bot 06c835
                  tmp->range.max = - INT_MAX;
Packit Bot 06c835
                  tmp->do_wrap = yes; /* may be set to no later */
Packit Bot 06c835
                  for (i = 0; i < NSYNTAXCHECKS; i++)
Packit Bot 06c835
                    tmp->do_syntax_check[i] = undecided; /* may be set to yes/no later */
Packit Bot 06c835
                  tmp->obsolete = true; /* may be set to false later */
Packit Bot 06c835
                  tmp->alternative_count = 0;
Packit Bot 06c835
                  tmp->alternative = NULL;
Packit Bot 06c835
                  message_list_append (total_mlp, tmp);
Packit Bot 06c835
                }
Packit Bot 06c835
Packit Bot 06c835
              if (!msgcomm_mode
Packit Bot 06c835
                  && ((!is_header (mp) && mp->is_fuzzy)
Packit Bot 06c835
                      || mp->msgstr[0] == '\0'))
Packit Bot 06c835
                /* Weak translation.  Counted as negative tmp->used.  */
Packit Bot 06c835
                {
Packit Bot 06c835
                  if (tmp->used <= 0)
Packit Bot 06c835
                    tmp->used--;
Packit Bot 06c835
                }
Packit Bot 06c835
              else
Packit Bot 06c835
                /* Good translation.  Counted as positive tmp->used.  */
Packit Bot 06c835
                {
Packit Bot 06c835
                  if (tmp->used < 0)
Packit Bot 06c835
                    tmp->used = 0;
Packit Bot 06c835
                  tmp->used++;
Packit Bot 06c835
                }
Packit Bot 06c835
              mp->tmp = tmp;
Packit Bot 06c835
            }
Packit Bot 06c835
        }
Packit Bot 06c835
    }
Packit Bot 06c835
Packit Bot 06c835
  /* Remove messages that are not used and need not be converted.  */
Packit Bot 06c835
  for (n = 0; n < nfiles; n++)
Packit Bot 06c835
    {
Packit Bot 06c835
      msgdomain_list_ty *mdlp = mdlps[n];
Packit Bot 06c835
      size_t k;
Packit Bot 06c835
Packit Bot 06c835
      for (k = 0; k < mdlp->nitems; k++)
Packit Bot 06c835
        {
Packit Bot 06c835
          message_list_ty *mlp = mdlp->item[k]->messages;
Packit Bot 06c835
Packit Bot 06c835
          message_list_remove_if_not (mlp,
Packit Bot 06c835
                                      use_first
Packit Bot 06c835
                                      ? is_message_first_needed
Packit Bot 06c835
                                      : is_message_needed);
Packit Bot 06c835
Packit Bot 06c835
          /* If no messages are remaining, drop the charset.  */
Packit Bot 06c835
          if (mlp->nitems == 0)
Packit Bot 06c835
            canon_charsets[n][k] = NULL;
Packit Bot 06c835
        }
Packit Bot 06c835
    }
Packit Bot 06c835
  {
Packit Bot 06c835
    size_t k;
Packit Bot 06c835
Packit Bot 06c835
    for (k = 0; k < total_mdlp->nitems; k++)
Packit Bot 06c835
      {
Packit Bot 06c835
        message_list_ty *mlp = total_mdlp->item[k]->messages;
Packit Bot 06c835
Packit Bot 06c835
        message_list_remove_if_not (mlp, is_message_selected);
Packit Bot 06c835
      }
Packit Bot 06c835
  }
Packit Bot 06c835
Packit Bot 06c835
  /* Determine the common known a-priori encoding, if any.  */
Packit Bot 06c835
  if (nfiles > 0)
Packit Bot 06c835
    {
Packit Bot 06c835
      bool all_same_encoding = true;
Packit Bot 06c835
Packit Bot 06c835
      for (n = 1; n < nfiles; n++)
Packit Bot 06c835
        if (mdlps[n]->encoding != mdlps[0]->encoding)
Packit Bot 06c835
          {
Packit Bot 06c835
            all_same_encoding = false;
Packit Bot 06c835
            break;
Packit Bot 06c835
          }
Packit Bot 06c835
Packit Bot 06c835
      if (all_same_encoding)
Packit Bot 06c835
        total_mdlp->encoding = mdlps[0]->encoding;
Packit Bot 06c835
    }
Packit Bot 06c835
Packit Bot 06c835
  /* Determine the target encoding for the remaining messages.  */
Packit Bot 06c835
  if (to_code != NULL)
Packit Bot 06c835
    {
Packit Bot 06c835
      /* Canonicalize target encoding.  */
Packit Bot 06c835
      canon_to_code = po_charset_canonicalize (to_code);
Packit Bot 06c835
      if (canon_to_code == NULL)
Packit Bot 06c835
        error (EXIT_FAILURE, 0,
Packit Bot 06c835
               _("target charset \"%s\" is not a portable encoding name."),
Packit Bot 06c835
               to_code);
Packit Bot 06c835
    }
Packit Bot 06c835
  else
Packit Bot 06c835
    {
Packit Bot 06c835
      /* No target encoding was specified.  Test whether the messages are
Packit Bot 06c835
         all in a single encoding.  If so, conversion is not needed.  */
Packit Bot 06c835
      const char *first = NULL;
Packit Bot 06c835
      const char *second = NULL;
Packit Bot 06c835
      bool with_ASCII = false;
Packit Bot 06c835
      bool with_UTF8 = false;
Packit Bot 06c835
      bool all_ASCII_compatible = true;
Packit Bot 06c835
Packit Bot 06c835
      for (n = 0; n < nfiles; n++)
Packit Bot 06c835
        {
Packit Bot 06c835
          msgdomain_list_ty *mdlp = mdlps[n];
Packit Bot 06c835
          size_t k;
Packit Bot 06c835
Packit Bot 06c835
          for (k = 0; k < mdlp->nitems; k++)
Packit Bot 06c835
            if (canon_charsets[n][k] != NULL)
Packit Bot 06c835
              {
Packit Bot 06c835
                if (canon_charsets[n][k] == po_charset_ascii)
Packit Bot 06c835
                  with_ASCII = true;
Packit Bot 06c835
                else
Packit Bot 06c835
                  {
Packit Bot 06c835
                    if (first == NULL)
Packit Bot 06c835
                      first = canon_charsets[n][k];
Packit Bot 06c835
                    else if (canon_charsets[n][k] != first && second == NULL)
Packit Bot 06c835
                      second = canon_charsets[n][k];
Packit Bot 06c835
Packit Bot 06c835
                    if (strcmp (canon_charsets[n][k], "UTF-8") == 0)
Packit Bot 06c835
                      with_UTF8 = true;
Packit Bot 06c835
Packit Bot 06c835
                    if (!po_charset_ascii_compatible (canon_charsets[n][k]))
Packit Bot 06c835
                      all_ASCII_compatible = false;
Packit Bot 06c835
                  }
Packit Bot 06c835
              }
Packit Bot 06c835
        }
Packit Bot 06c835
Packit Bot 06c835
      if (with_ASCII && !all_ASCII_compatible)
Packit Bot 06c835
        {
Packit Bot 06c835
          /* assert (first != NULL); */
Packit Bot 06c835
          if (second == NULL)
Packit Bot 06c835
            second = po_charset_ascii;
Packit Bot 06c835
        }
Packit Bot 06c835
Packit Bot 06c835
      if (second != NULL)
Packit Bot 06c835
        {
Packit Bot 06c835
          /* A conversion is needed.  Warn the user since he hasn't asked
Packit Bot 06c835
             for it and might be surprised.  */
Packit Bot 06c835
          if (with_UTF8)
Packit Bot 06c835
            multiline_warning (xasprintf (_("warning: ")),
Packit Bot 06c835
                               xasprintf (_("\
Packit Bot 06c835
Input files contain messages in different encodings, UTF-8 among others.\n\
Packit Bot 06c835
Converting the output to UTF-8.\n\
Packit Bot 06c835
")));
Packit Bot 06c835
          else
Packit Bot 06c835
            multiline_warning (xasprintf (_("warning: ")),
Packit Bot 06c835
                               xasprintf (_("\
Packit Bot 06c835
Input files contain messages in different encodings, %s and %s among others.\n\
Packit Bot 06c835
Converting the output to UTF-8.\n\
Packit Bot 06c835
To select a different output encoding, use the --to-code option.\n\
Packit Bot 06c835
"), first, second));
Packit Bot 06c835
          canon_to_code = po_charset_utf8;
Packit Bot 06c835
        }
Packit Bot 06c835
      else if (first != NULL && with_ASCII && all_ASCII_compatible)
Packit Bot 06c835
        {
Packit Bot 06c835
          /* The conversion is a no-op conversion.  Don't warn the user,
Packit Bot 06c835
             but still perform the conversion, in order to check that the
Packit Bot 06c835
             input was really ASCII.  */
Packit Bot 06c835
          canon_to_code = first;
Packit Bot 06c835
        }
Packit Bot 06c835
      else
Packit Bot 06c835
        {
Packit Bot 06c835
          /* No conversion needed.  */
Packit Bot 06c835
          canon_to_code = NULL;
Packit Bot 06c835
        }
Packit Bot 06c835
    }
Packit Bot 06c835
Packit Bot 06c835
  /* Now convert the remaining messages to to_code.  */
Packit Bot 06c835
  if (canon_to_code != NULL)
Packit Bot 06c835
    for (n = 0; n < nfiles; n++)
Packit Bot 06c835
      {
Packit Bot 06c835
        msgdomain_list_ty *mdlp = mdlps[n];
Packit Bot 06c835
        size_t k;
Packit Bot 06c835
Packit Bot 06c835
        for (k = 0; k < mdlp->nitems; k++)
Packit Bot 06c835
          if (canon_charsets[n][k] != NULL)
Packit Bot 06c835
            /* If the user hasn't given a to_code, don't bother doing a noop
Packit Bot 06c835
               conversion that would only replace the charset name in the
Packit Bot 06c835
               header entry with its canonical equivalent.  */
Packit Bot 06c835
            if (!(to_code == NULL && canon_charsets[n][k] == canon_to_code))
Packit Bot 06c835
              if (iconv_message_list (mdlp->item[k]->messages,
Packit Bot 06c835
                                      canon_charsets[n][k], canon_to_code,
Packit Bot 06c835
                                      files[n]))
Packit Bot 06c835
                {
Packit Bot 06c835
                  multiline_error (xstrdup (""),
Packit Bot 06c835
                                   xasprintf (_("\
Packit Bot 06c835
Conversion of file %s from %s encoding to %s encoding\n\
Packit Bot 06c835
changes some msgids or msgctxts.\n\
Packit Bot 06c835
Either change all msgids and msgctxts to be pure ASCII, or ensure they are\n\
Packit Bot 06c835
UTF-8 encoded from the beginning, i.e. already in your source code files.\n"),
Packit Bot 06c835
                                              files[n], canon_charsets[n][k],
Packit Bot 06c835
                                              canon_to_code));
Packit Bot 06c835
                  exit (EXIT_FAILURE);
Packit Bot 06c835
                }
Packit Bot 06c835
      }
Packit Bot 06c835
Packit Bot 06c835
  /* Fill the resulting messages.  */
Packit Bot 06c835
  for (n = 0; n < nfiles; n++)
Packit Bot 06c835
    {
Packit Bot 06c835
      msgdomain_list_ty *mdlp = mdlps[n];
Packit Bot 06c835
      size_t k;
Packit Bot 06c835
Packit Bot 06c835
      for (k = 0; k < mdlp->nitems; k++)
Packit Bot 06c835
        {
Packit Bot 06c835
          message_list_ty *mlp = mdlp->item[k]->messages;
Packit Bot 06c835
Packit Bot 06c835
          for (j = 0; j < mlp->nitems; j++)
Packit Bot 06c835
            {
Packit Bot 06c835
              message_ty *mp = mlp->item[j];
Packit Bot 06c835
              message_ty *tmp = mp->tmp;
Packit Bot 06c835
              size_t i;
Packit Bot 06c835
Packit Bot 06c835
              /* No need to discard unneeded weak translations here;
Packit Bot 06c835
                 they have already been filtered out above.  */
Packit Bot 06c835
              if (use_first || tmp->used == 1 || tmp->used == -1)
Packit Bot 06c835
                {
Packit Bot 06c835
                  /* Copy mp, as only message, into tmp.  */
Packit Bot 06c835
                  tmp->msgstr = mp->msgstr;
Packit Bot 06c835
                  tmp->msgstr_len = mp->msgstr_len;
Packit Bot 06c835
                  tmp->pos = mp->pos;
Packit Bot 06c835
                  if (mp->comment)
Packit Bot 06c835
                    for (i = 0; i < mp->comment->nitems; i++)
Packit Bot 06c835
                      message_comment_append (tmp, mp->comment->item[i]);
Packit Bot 06c835
                  if (mp->comment_dot)
Packit Bot 06c835
                    for (i = 0; i < mp->comment_dot->nitems; i++)
Packit Bot 06c835
                      message_comment_dot_append (tmp,
Packit Bot 06c835
                                                  mp->comment_dot->item[i]);
Packit Bot 06c835
                  for (i = 0; i < mp->filepos_count; i++)
Packit Bot 06c835
                    message_comment_filepos (tmp, mp->filepos[i].file_name,
Packit Bot 06c835
                                             mp->filepos[i].line_number);
Packit Bot 06c835
                  tmp->is_fuzzy = mp->is_fuzzy;
Packit Bot 06c835
                  for (i = 0; i < NFORMATS; i++)
Packit Bot 06c835
                    tmp->is_format[i] = mp->is_format[i];
Packit Bot 06c835
                  tmp->range = mp->range;
Packit Bot 06c835
                  tmp->do_wrap = mp->do_wrap;
Packit Bot 06c835
                  for (i = 0; i < NSYNTAXCHECKS; i++)
Packit Bot 06c835
                    tmp->do_syntax_check[i] = mp->do_syntax_check[i];
Packit Bot 06c835
                  tmp->prev_msgctxt = mp->prev_msgctxt;
Packit Bot 06c835
                  tmp->prev_msgid = mp->prev_msgid;
Packit Bot 06c835
                  tmp->prev_msgid_plural = mp->prev_msgid_plural;
Packit Bot 06c835
                  tmp->obsolete = mp->obsolete;
Packit Bot 06c835
                }
Packit Bot 06c835
              else if (msgcomm_mode)
Packit Bot 06c835
                {
Packit Bot 06c835
                  /* Copy mp, as only message, into tmp.  */
Packit Bot 06c835
                  if (tmp->msgstr == NULL)
Packit Bot 06c835
                    {
Packit Bot 06c835
                      tmp->msgstr = mp->msgstr;
Packit Bot 06c835
                      tmp->msgstr_len = mp->msgstr_len;
Packit Bot 06c835
                      tmp->pos = mp->pos;
Packit Bot 06c835
                      tmp->is_fuzzy = mp->is_fuzzy;
Packit Bot 06c835
                      tmp->prev_msgctxt = mp->prev_msgctxt;
Packit Bot 06c835
                      tmp->prev_msgid = mp->prev_msgid;
Packit Bot 06c835
                      tmp->prev_msgid_plural = mp->prev_msgid_plural;
Packit Bot 06c835
                    }
Packit Bot 06c835
                  if (mp->comment && tmp->comment == NULL)
Packit Bot 06c835
                    for (i = 0; i < mp->comment->nitems; i++)
Packit Bot 06c835
                      message_comment_append (tmp, mp->comment->item[i]);
Packit Bot 06c835
                  if (mp->comment_dot && tmp->comment_dot == NULL)
Packit Bot 06c835
                    for (i = 0; i < mp->comment_dot->nitems; i++)
Packit Bot 06c835
                      message_comment_dot_append (tmp,
Packit Bot 06c835
                                                  mp->comment_dot->item[i]);
Packit Bot 06c835
                  for (i = 0; i < mp->filepos_count; i++)
Packit Bot 06c835
                    message_comment_filepos (tmp, mp->filepos[i].file_name,
Packit Bot 06c835
                                             mp->filepos[i].line_number);
Packit Bot 06c835
                  for (i = 0; i < NFORMATS; i++)
Packit Bot 06c835
                    if (tmp->is_format[i] == undecided)
Packit Bot 06c835
                      tmp->is_format[i] = mp->is_format[i];
Packit Bot 06c835
                  if (tmp->range.min == - INT_MAX
Packit Bot 06c835
                      && tmp->range.max == - INT_MAX)
Packit Bot 06c835
                    tmp->range = mp->range;
Packit Bot 06c835
                  else if (has_range_p (mp->range) && has_range_p (tmp->range))
Packit Bot 06c835
                    {
Packit Bot 06c835
                      if (mp->range.min < tmp->range.min)
Packit Bot 06c835
                        tmp->range.min = mp->range.min;
Packit Bot 06c835
                      if (mp->range.max > tmp->range.max)
Packit Bot 06c835
                        tmp->range.max = mp->range.max;
Packit Bot 06c835
                    }
Packit Bot 06c835
                  else
Packit Bot 06c835
                    {
Packit Bot 06c835
                      tmp->range.min = -1;
Packit Bot 06c835
                      tmp->range.max = -1;
Packit Bot 06c835
                    }
Packit Bot 06c835
                  if (tmp->do_wrap == undecided)
Packit Bot 06c835
                    tmp->do_wrap = mp->do_wrap;
Packit Bot 06c835
                  for (i = 0; i < NSYNTAXCHECKS; i++)
Packit Bot 06c835
                    if (tmp->do_syntax_check[i] == undecided)
Packit Bot 06c835
                      tmp->do_syntax_check[i] = mp->do_syntax_check[i];
Packit Bot 06c835
                  tmp->obsolete = false;
Packit Bot 06c835
                }
Packit Bot 06c835
              else
Packit Bot 06c835
                {
Packit Bot 06c835
                  /* Copy mp, among others, into tmp.  */
Packit Bot 06c835
                  char *id = xasprintf ("#-#-#-#-#  %s  #-#-#-#-#",
Packit Bot 06c835
                                        identifications[n][k]);
Packit Bot 06c835
                  size_t nbytes;
Packit Bot 06c835
Packit Bot 06c835
                  if (tmp->alternative_count == 0)
Packit Bot 06c835
                    tmp->pos = mp->pos;
Packit Bot 06c835
Packit Bot 06c835
                  i = tmp->alternative_count;
Packit Bot 06c835
                  nbytes = (i + 1) * sizeof (struct altstr);
Packit Bot 06c835
                  tmp->alternative = xrealloc (tmp->alternative, nbytes);
Packit Bot 06c835
                  tmp->alternative[i].msgstr = mp->msgstr;
Packit Bot 06c835
                  tmp->alternative[i].msgstr_len = mp->msgstr_len;
Packit Bot 06c835
                  tmp->alternative[i].msgstr_end =
Packit Bot 06c835
                    tmp->alternative[i].msgstr + tmp->alternative[i].msgstr_len;
Packit Bot 06c835
                  tmp->alternative[i].comment = mp->comment;
Packit Bot 06c835
                  tmp->alternative[i].comment_dot = mp->comment_dot;
Packit Bot 06c835
                  tmp->alternative[i].id = id;
Packit Bot 06c835
                  tmp->alternative_count = i + 1;
Packit Bot 06c835
Packit Bot 06c835
                  for (i = 0; i < mp->filepos_count; i++)
Packit Bot 06c835
                    message_comment_filepos (tmp, mp->filepos[i].file_name,
Packit Bot 06c835
                                             mp->filepos[i].line_number);
Packit Bot 06c835
                  if (!mp->is_fuzzy)
Packit Bot 06c835
                    tmp->is_fuzzy = false;
Packit Bot 06c835
                  for (i = 0; i < NFORMATS; i++)
Packit Bot 06c835
                    if (mp->is_format[i] == yes)
Packit Bot 06c835
                      tmp->is_format[i] = yes;
Packit Bot 06c835
                    else if (mp->is_format[i] == no
Packit Bot 06c835
                             && tmp->is_format[i] == undecided)
Packit Bot 06c835
                      tmp->is_format[i] = no;
Packit Bot 06c835
                  if (tmp->range.min == - INT_MAX
Packit Bot 06c835
                      && tmp->range.max == - INT_MAX)
Packit Bot 06c835
                    tmp->range = mp->range;
Packit Bot 06c835
                  else if (has_range_p (mp->range) && has_range_p (tmp->range))
Packit Bot 06c835
                    {
Packit Bot 06c835
                      if (mp->range.min < tmp->range.min)
Packit Bot 06c835
                        tmp->range.min = mp->range.min;
Packit Bot 06c835
                      if (mp->range.max > tmp->range.max)
Packit Bot 06c835
                        tmp->range.max = mp->range.max;
Packit Bot 06c835
                    }
Packit Bot 06c835
                  else
Packit Bot 06c835
                    {
Packit Bot 06c835
                      tmp->range.min = -1;
Packit Bot 06c835
                      tmp->range.max = -1;
Packit Bot 06c835
                    }
Packit Bot 06c835
                  if (mp->do_wrap == no)
Packit Bot 06c835
                    tmp->do_wrap = no;
Packit Bot 06c835
                  for (i = 0; i < NSYNTAXCHECKS; i++)
Packit Bot 06c835
                    if (mp->do_syntax_check[i] == yes)
Packit Bot 06c835
                      tmp->do_syntax_check[i] = yes;
Packit Bot 06c835
                    else if (mp->do_syntax_check[i] == no
Packit Bot 06c835
                             && tmp->do_syntax_check[i] == undecided)
Packit Bot 06c835
                      tmp->do_syntax_check[i] = no;
Packit Bot 06c835
                  /* Don't fill tmp->prev_msgid in this case.  */
Packit Bot 06c835
                  if (!mp->obsolete)
Packit Bot 06c835
                    tmp->obsolete = false;
Packit Bot 06c835
                }
Packit Bot 06c835
            }
Packit Bot 06c835
        }
Packit Bot 06c835
    }
Packit Bot 06c835
  {
Packit Bot 06c835
    size_t k;
Packit Bot 06c835
Packit Bot 06c835
    for (k = 0; k < total_mdlp->nitems; k++)
Packit Bot 06c835
      {
Packit Bot 06c835
        message_list_ty *mlp = total_mdlp->item[k]->messages;
Packit Bot 06c835
Packit Bot 06c835
        for (j = 0; j < mlp->nitems; j++)
Packit Bot 06c835
          {
Packit Bot 06c835
            message_ty *tmp = mlp->item[j];
Packit Bot 06c835
Packit Bot 06c835
            if (tmp->alternative_count > 0)
Packit Bot 06c835
              {
Packit Bot 06c835
                /* Test whether all alternative translations are equal.  */
Packit Bot 06c835
                struct altstr *first = &tmp->alternative[0];
Packit Bot 06c835
                size_t i;
Packit Bot 06c835
Packit Bot 06c835
                for (i = 0; i < tmp->alternative_count; i++)
Packit Bot 06c835
                  if (!(tmp->alternative[i].msgstr_len == first->msgstr_len
Packit Bot 06c835
                        && memcmp (tmp->alternative[i].msgstr, first->msgstr,
Packit Bot 06c835
                                   first->msgstr_len) == 0))
Packit Bot 06c835
                    break;
Packit Bot 06c835
Packit Bot 06c835
                if (i == tmp->alternative_count)
Packit Bot 06c835
                  {
Packit Bot 06c835
                    /* All alternatives are equal.  */
Packit Bot 06c835
                    tmp->msgstr = first->msgstr;
Packit Bot 06c835
                    tmp->msgstr_len = first->msgstr_len;
Packit Bot 06c835
                  }
Packit Bot 06c835
                else
Packit Bot 06c835
                  {
Packit Bot 06c835
                    /* Concatenate the alternative msgstrs into a single one,
Packit Bot 06c835
                       separated by markers.  */
Packit Bot 06c835
                    size_t len;
Packit Bot 06c835
                    const char *p;
Packit Bot 06c835
                    const char *p_end;
Packit Bot 06c835
                    char *new_msgstr;
Packit Bot 06c835
                    char *np;
Packit Bot 06c835
Packit Bot 06c835
                    len = 0;
Packit Bot 06c835
                    for (i = 0; i < tmp->alternative_count; i++)
Packit Bot 06c835
                      {
Packit Bot 06c835
                        size_t id_len = strlen (tmp->alternative[i].id);
Packit Bot 06c835
Packit Bot 06c835
                        len += tmp->alternative[i].msgstr_len;
Packit Bot 06c835
Packit Bot 06c835
                        p = tmp->alternative[i].msgstr;
Packit Bot 06c835
                        p_end = tmp->alternative[i].msgstr_end;
Packit Bot 06c835
                        for (; p < p_end; p += strlen (p) + 1)
Packit Bot 06c835
                          len += id_len + 2;
Packit Bot 06c835
                      }
Packit Bot 06c835
Packit Bot 06c835
                    new_msgstr = XNMALLOC (len, char);
Packit Bot 06c835
                    np = new_msgstr;
Packit Bot 06c835
                    for (;;)
Packit Bot 06c835
                      {
Packit Bot 06c835
                        /* Test whether there's one more plural form to
Packit Bot 06c835
                           process.  */
Packit Bot 06c835
                        for (i = 0; i < tmp->alternative_count; i++)
Packit Bot 06c835
                          if (tmp->alternative[i].msgstr
Packit Bot 06c835
                              < tmp->alternative[i].msgstr_end)
Packit Bot 06c835
                            break;
Packit Bot 06c835
                        if (i == tmp->alternative_count)
Packit Bot 06c835
                          break;
Packit Bot 06c835
Packit Bot 06c835
                        /* Process next plural form.  */
Packit Bot 06c835
                        for (i = 0; i < tmp->alternative_count; i++)
Packit Bot 06c835
                          if (tmp->alternative[i].msgstr
Packit Bot 06c835
                              < tmp->alternative[i].msgstr_end)
Packit Bot 06c835
                            {
Packit Bot 06c835
                              if (np > new_msgstr && np[-1] != '\0'
Packit Bot 06c835
                                  && np[-1] != '\n')
Packit Bot 06c835
                                *np++ = '\n';
Packit Bot 06c835
Packit Bot 06c835
                              len = strlen (tmp->alternative[i].id);
Packit Bot 06c835
                              memcpy (np, tmp->alternative[i].id, len);
Packit Bot 06c835
                              np += len;
Packit Bot 06c835
                              *np++ = '\n';
Packit Bot 06c835
Packit Bot 06c835
                              len = strlen (tmp->alternative[i].msgstr);
Packit Bot 06c835
                              memcpy (np, tmp->alternative[i].msgstr, len);
Packit Bot 06c835
                              np += len;
Packit Bot 06c835
                              tmp->alternative[i].msgstr += len + 1;
Packit Bot 06c835
                            }
Packit Bot 06c835
Packit Bot 06c835
                        /* Plural forms are separated by NUL bytes.  */
Packit Bot 06c835
                        *np++ = '\0';
Packit Bot 06c835
                      }
Packit Bot 06c835
                    tmp->msgstr = new_msgstr;
Packit Bot 06c835
                    tmp->msgstr_len = np - new_msgstr;
Packit Bot 06c835
Packit Bot 06c835
                    tmp->is_fuzzy = true;
Packit Bot 06c835
                  }
Packit Bot 06c835
Packit Bot 06c835
                /* Test whether all alternative comments are equal.  */
Packit Bot 06c835
                for (i = 0; i < tmp->alternative_count; i++)
Packit Bot 06c835
                  if (tmp->alternative[i].comment == NULL
Packit Bot 06c835
                      || !string_list_equal (tmp->alternative[i].comment,
Packit Bot 06c835
                                             first->comment))
Packit Bot 06c835
                    break;
Packit Bot 06c835
Packit Bot 06c835
                if (i == tmp->alternative_count)
Packit Bot 06c835
                  /* All alternatives are equal.  */
Packit Bot 06c835
                  tmp->comment = first->comment;
Packit Bot 06c835
                else
Packit Bot 06c835
                  /* Concatenate the alternative comments into a single one,
Packit Bot 06c835
                     separated by markers.  */
Packit Bot 06c835
                  for (i = 0; i < tmp->alternative_count; i++)
Packit Bot 06c835
                    {
Packit Bot 06c835
                      string_list_ty *slp = tmp->alternative[i].comment;
Packit Bot 06c835
Packit Bot 06c835
                      if (slp != NULL)
Packit Bot 06c835
                        {
Packit Bot 06c835
                          size_t l;
Packit Bot 06c835
Packit Bot 06c835
                          message_comment_append (tmp, tmp->alternative[i].id);
Packit Bot 06c835
                          for (l = 0; l < slp->nitems; l++)
Packit Bot 06c835
                            message_comment_append (tmp, slp->item[l]);
Packit Bot 06c835
                        }
Packit Bot 06c835
                    }
Packit Bot 06c835
Packit Bot 06c835
                /* Test whether all alternative dot comments are equal.  */
Packit Bot 06c835
                for (i = 0; i < tmp->alternative_count; i++)
Packit Bot 06c835
                  if (tmp->alternative[i].comment_dot == NULL
Packit Bot 06c835
                      || !string_list_equal (tmp->alternative[i].comment_dot,
Packit Bot 06c835
                                             first->comment_dot))
Packit Bot 06c835
                    break;
Packit Bot 06c835
Packit Bot 06c835
                if (i == tmp->alternative_count)
Packit Bot 06c835
                  /* All alternatives are equal.  */
Packit Bot 06c835
                  tmp->comment_dot = first->comment_dot;
Packit Bot 06c835
                else
Packit Bot 06c835
                  /* Concatenate the alternative dot comments into a single one,
Packit Bot 06c835
                     separated by markers.  */
Packit Bot 06c835
                  for (i = 0; i < tmp->alternative_count; i++)
Packit Bot 06c835
                    {
Packit Bot 06c835
                      string_list_ty *slp = tmp->alternative[i].comment_dot;
Packit Bot 06c835
Packit Bot 06c835
                      if (slp != NULL)
Packit Bot 06c835
                        {
Packit Bot 06c835
                          size_t l;
Packit Bot 06c835
Packit Bot 06c835
                          message_comment_dot_append (tmp,
Packit Bot 06c835
                                                      tmp->alternative[i].id);
Packit Bot 06c835
                          for (l = 0; l < slp->nitems; l++)
Packit Bot 06c835
                            message_comment_dot_append (tmp, slp->item[l]);
Packit Bot 06c835
                        }
Packit Bot 06c835
                    }
Packit Bot 06c835
              }
Packit Bot 06c835
          }
Packit Bot 06c835
      }
Packit Bot 06c835
  }
Packit Bot 06c835
Packit Bot 06c835
  return total_mdlp;
Packit Bot 06c835
}