--- /dev/null
+/* GNU gettext - internationalization aids
+ Copyright (C) 1995-1998, 2000-2006 Free Software Foundation, Inc.
+
+ 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+/* Specification. */
+#include "write-catalog.h"
+
+#include <errno.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "fwriteerror.h"
+#include "error-progname.h"
+#include "xvasprintf.h"
+#include "po-xerror.h"
+#include "gettext.h"
+
+/* Our regular abbreviation. */
+#define _(str) gettext (str)
+
+
+/* =========== Some parameters for use by 'msgdomain_list_print'. ========== */
+
+
+/* This variable controls the page width when printing messages.
+ Defaults to PAGE_WIDTH if not set. Zero (0) given to message_page_-
+ width_set will result in no wrapping being performed. */
+static size_t page_width = PAGE_WIDTH;
+
+void
+message_page_width_set (size_t n)
+{
+ if (n == 0)
+ {
+ page_width = INT_MAX;
+ return;
+ }
+
+ if (n < 20)
+ n = 20;
+
+ page_width = n;
+}
+
+
+/* ======================== msgdomain_list_print() ======================== */
+
+
+void
+msgdomain_list_print (msgdomain_list_ty *mdlp, const char *filename,
+ catalog_output_format_ty output_syntax,
+ bool force, bool debug)
+{
+ FILE *fp;
+
+ /* We will not write anything if, for every domain, we have no message
+ or only the header entry. */
+ if (!force)
+ {
+ bool found_nonempty = false;
+ size_t k;
+
+ for (k = 0; k < mdlp->nitems; k++)
+ {
+ message_list_ty *mlp = mdlp->item[k]->messages;
+
+ if (!(mlp->nitems == 0
+ || (mlp->nitems == 1 && is_header (mlp->item[0]))))
+ {
+ found_nonempty = true;
+ break;
+ }
+ }
+
+ if (!found_nonempty)
+ return;
+ }
+
+ /* Check whether the output format can accomodate all messages. */
+ if (!output_syntax->supports_multiple_domains && mdlp->nitems > 1)
+ {
+ if (output_syntax->alternative_is_po)
+ po_xerror (PO_SEVERITY_FATAL_ERROR, NULL, NULL, 0, 0, false, _("\
+Cannot output multiple translation domains into a single file with the specified output format. Try using PO file syntax instead."));
+ else
+ po_xerror (PO_SEVERITY_FATAL_ERROR, NULL, NULL, 0, 0, false, _("\
+Cannot output multiple translation domains into a single file with the specified output format."));
+ }
+ else
+ {
+ if (!output_syntax->supports_contexts)
+ {
+ const lex_pos_ty *has_context;
+ size_t k;
+
+ has_context = NULL;
+ for (k = 0; k < mdlp->nitems; k++)
+ {
+ message_list_ty *mlp = mdlp->item[k]->messages;
+ size_t j;
+
+ for (j = 0; j < mlp->nitems; j++)
+ {
+ message_ty *mp = mlp->item[j];
+
+ if (mp->msgctxt != NULL)
+ {
+ has_context = &mp->pos;
+ break;
+ }
+ }
+ }
+
+ if (has_context != NULL)
+ {
+ error_with_progname = false;
+ po_xerror (PO_SEVERITY_FATAL_ERROR, NULL,
+ has_context->file_name, has_context->line_number,
+ (size_t)(-1), false, _("\
+message catalog has context dependent translations, but the output format does not support them."));
+ error_with_progname = true;
+ }
+ }
+
+ if (!output_syntax->supports_plurals)
+ {
+ const lex_pos_ty *has_plural;
+ size_t k;
+
+ has_plural = NULL;
+ for (k = 0; k < mdlp->nitems; k++)
+ {
+ message_list_ty *mlp = mdlp->item[k]->messages;
+ size_t j;
+
+ for (j = 0; j < mlp->nitems; j++)
+ {
+ message_ty *mp = mlp->item[j];
+
+ if (mp->msgid_plural != NULL)
+ {
+ has_plural = &mp->pos;
+ break;
+ }
+ }
+ }
+
+ if (has_plural != NULL)
+ {
+ error_with_progname = false;
+ if (output_syntax->alternative_is_java_class)
+ po_xerror (PO_SEVERITY_FATAL_ERROR, NULL,
+ has_plural->file_name, has_plural->line_number,
+ (size_t)(-1), false, _("\
+message catalog has plural form translations, but the output format does not support them. Try generating a Java class using \"msgfmt --java\", instead of a properties file."));
+ else
+ po_xerror (PO_SEVERITY_FATAL_ERROR, NULL,
+ has_plural->file_name, has_plural->line_number,
+ (size_t)(-1), false, _("\
+message catalog has plural form translations, but the output format does not support them."));
+ error_with_progname = true;
+ }
+ }
+ }
+
+ /* Open the output file. */
+ if (filename != NULL && strcmp (filename, "-") != 0
+ && strcmp (filename, "/dev/stdout") != 0)
+ {
+ fp = fopen (filename, "w");
+ if (fp == NULL)
+ {
+ const char *errno_description = strerror (errno);
+ po_xerror (PO_SEVERITY_FATAL_ERROR, NULL, NULL, 0, 0, false,
+ xasprintf ("%s: %s",
+ xasprintf (_("cannot create output file \"%s\""),
+ filename),
+ errno_description));
+ }
+ }
+ else
+ {
+ fp = stdout;
+ /* xgettext:no-c-format */
+ filename = _("standard output");
+ }
+
+ output_syntax->print (mdlp, fp, page_width, debug);
+
+ /* Make sure nothing went wrong. */
+ if (fwriteerror (fp))
+ {
+ const char *errno_description = strerror (errno);
+ po_xerror (PO_SEVERITY_FATAL_ERROR, NULL, NULL, 0, 0, false,
+ xasprintf ("%s: %s",
+ xasprintf (_("error while writing \"%s\" file"),
+ filename),
+ errno_description));
+ }
+}
+
+
+/* =============================== Sorting. ================================ */
+
+
+static int
+cmp_by_msgid (const void *va, const void *vb)
+{
+ const message_ty *a = *(const message_ty **) va;
+ const message_ty *b = *(const message_ty **) vb;
+ /* Because msgids normally contain only ASCII characters, it is OK to
+ sort them as if we were in the C locale. And strcoll() in the C locale
+ is the same as strcmp(). */
+ return strcmp (a->msgid, b->msgid);
+}
+
+
+void
+msgdomain_list_sort_by_msgid (msgdomain_list_ty *mdlp)
+{
+ size_t k;
+
+ for (k = 0; k < mdlp->nitems; k++)
+ {
+ message_list_ty *mlp = mdlp->item[k]->messages;
+
+ if (mlp->nitems > 0)
+ qsort (mlp->item, mlp->nitems, sizeof (mlp->item[0]), cmp_by_msgid);
+ }
+}
+
+
+/* Sort the file positions of every message. */
+
+static int
+cmp_filepos (const void *va, const void *vb)
+{
+ const lex_pos_ty *a = (const lex_pos_ty *) va;
+ const lex_pos_ty *b = (const lex_pos_ty *) vb;
+ int cmp;
+
+ cmp = strcmp (a->file_name, b->file_name);
+ if (cmp == 0)
+ cmp = (int) a->line_number - (int) b->line_number;
+
+ return cmp;
+}
+
+static void
+msgdomain_list_sort_filepos (msgdomain_list_ty *mdlp)
+{
+ size_t j, k;
+
+ for (k = 0; k < mdlp->nitems; k++)
+ {
+ message_list_ty *mlp = mdlp->item[k]->messages;
+
+ for (j = 0; j < mlp->nitems; j++)
+ {
+ message_ty *mp = mlp->item[j];
+
+ if (mp->filepos_count > 0)
+ qsort (mp->filepos, mp->filepos_count, sizeof (mp->filepos[0]),
+ cmp_filepos);
+ }
+ }
+}
+
+
+/* Sort the messages according to the file position. */
+
+static int
+cmp_by_filepos (const void *va, const void *vb)
+{
+ const message_ty *a = *(const message_ty **) va;
+ const message_ty *b = *(const message_ty **) vb;
+ int cmp;
+
+ /* No filepos is smaller than any other filepos. */
+ if (a->filepos_count == 0)
+ {
+ if (b->filepos_count != 0)
+ return -1;
+ }
+ if (b->filepos_count == 0)
+ return 1;
+
+ /* Compare on the file names... */
+ cmp = strcmp (a->filepos[0].file_name, b->filepos[0].file_name);
+ if (cmp != 0)
+ return cmp;
+
+ /* If they are equal, compare on the line numbers... */
+ cmp = a->filepos[0].line_number - b->filepos[0].line_number;
+ if (cmp != 0)
+ return cmp;
+
+ /* If they are equal, compare on the msgid strings. */
+ /* Because msgids normally contain only ASCII characters, it is OK to
+ sort them as if we were in the C locale. And strcoll() in the C locale
+ is the same as strcmp(). */
+ return strcmp (a->msgid, b->msgid);
+}
+
+
+void
+msgdomain_list_sort_by_filepos (msgdomain_list_ty *mdlp)
+{
+ size_t k;
+
+ /* It makes sense to compare filepos[0] of different messages only after
+ the filepos[] array of each message has been sorted. Sort it now. */
+ msgdomain_list_sort_filepos (mdlp);
+
+ for (k = 0; k < mdlp->nitems; k++)
+ {
+ message_list_ty *mlp = mdlp->item[k]->messages;
+
+ if (mlp->nitems > 0)
+ qsort (mlp->item, mlp->nitems, sizeof (mlp->item[0]), cmp_by_filepos);
+ }
+}
--- /dev/null
+/* GNU gettext - internationalization aids
+ Copyright (C) 1995-1998, 2000-2003, 2006 Free Software Foundation, Inc.
+
+ 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
+
+#ifndef _WRITE_CATALOG_H
+#define _WRITE_CATALOG_H
+
+#include <stdbool.h>
+#include <stdio.h>
+
+#include "message.h"
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/* This structure describes a textual catalog output format. */
+struct catalog_output_format
+{
+ /* Outputs a list of domains of messages to a file. */
+ void (*print) (msgdomain_list_ty *mdlp, FILE *fp, size_t page_width, bool debug);
+
+ /* Whether the print function requires the MDLP to be encoded in UTF-8
+ encoding. */
+ bool requires_utf8;
+
+ /* Whether the format supports multiple domains in a single file. */
+ bool supports_multiple_domains;
+
+ /* Whether the format supports contexts. */
+ bool supports_contexts;
+
+ /* Whether the format supports plurals. */
+ bool supports_plurals;
+
+ /* Whether the PO file format is a suitable alternative output format for
+ this one. */
+ bool alternative_is_po;
+
+ /* Whether a Java class is a suitable alternative output format for this
+ one. */
+ bool alternative_is_java_class;
+};
+
+typedef const struct catalog_output_format * catalog_output_format_ty;
+
+/* These functions set some parameters for use by 'msgdomain_list_print'. */
+extern void
+ message_page_width_set (size_t width);
+
+/* Output MDLP into a PO file with the given FILENAME, according to the
+ parameters set by the functions above. */
+extern void
+ msgdomain_list_print (msgdomain_list_ty *mdlp,
+ const char *filename,
+ catalog_output_format_ty output_syntax,
+ bool force, bool debug);
+
+/* Sort MDLP destructively according to the given criterion. */
+extern void
+ msgdomain_list_sort_by_msgid (msgdomain_list_ty *mdlp);
+extern void
+ msgdomain_list_sort_by_filepos (msgdomain_list_ty *mdlp);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif /* _WRITE_CATALOG_H */