Hello community, here is the log from the commit of package gettext-runtime for openSUSE:Factory checked in at 2020-10-06 17:05:56 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/gettext-runtime (Old) and /work/SRC/openSUSE:Factory/.gettext-runtime.new.4249 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "gettext-runtime" Tue Oct 6 17:05:56 2020 rev:85 rq:825378 version:0.21 Changes: -------- --- /work/SRC/openSUSE:Factory/gettext-runtime/gettext-csharp.changes 2020-01-25 13:22:51.504002330 +0100 +++ /work/SRC/openSUSE:Factory/.gettext-runtime.new.4249/gettext-csharp.changes 2020-10-06 17:06:01.985264162 +0200 @@ -1,0 +2,9 @@ +Tue Jul 28 10:33:41 UTC 2020 - Christian Vögl <[email protected]> + +-Updated to version 0.21 + * Improvements for translators: + When msgfmt writes a MO file, it now does so in such a way that processes + that are currently using an older copy of the MO file will not crash. + + +------------------------------------------------------------------- --- /work/SRC/openSUSE:Factory/gettext-runtime/gettext-java.changes 2020-01-25 13:22:53.388003155 +0100 +++ /work/SRC/openSUSE:Factory/.gettext-runtime.new.4249/gettext-java.changes 2020-10-06 17:06:05.009266773 +0200 @@ -1,0 +2,12 @@ +Tue Jul 28 10:20:58 UTC 2020 - Christian Vögl <[email protected]> + +- Updated to version 0.21 + - Java: + o xgettext now recognizes format strings in the Formatter syntax. They + are marked as 'java-printf-format' in POT and PO files. + o xgettext now recognizes text blocks as string literals. + - Improvements for translators: + o When msgfmt writes a MO file, it now does so in such a way that processes + that are currently using an older copy of the MO file will not crash. + +------------------------------------------------------------------- --- /work/SRC/openSUSE:Factory/gettext-runtime/gettext-runtime-mini.changes 2020-07-15 11:11:35.988795680 +0200 +++ /work/SRC/openSUSE:Factory/.gettext-runtime.new.4249/gettext-runtime-mini.changes 2020-10-06 17:06:06.981268477 +0200 @@ -1,0 +2,36 @@ +Fri Aug 7 07:46:39 UTC 2020 - Marketa Calabkova <[email protected]> + +- Add multiple new features (bsc#1165138) +- Add patches: + * 0001-msgcat-Add-feature-to-use-the-newest-po-file.patch + * 0002-msgcat-Merge-headers-when-use-first.patch +- Reintroduce autoreconf call + +------------------------------------------------------------------- +Tue Jul 28 09:33:34 UTC 2020 - Christian Vögl <[email protected]> + +- Update to 0.21: + * Programming languages support: + - Shell: + o xgettext now recognizes and ignores 'env' invocations and environment + variable assignments in front of commands. + - Java: + o xgettext now recognizes format strings in the Formatter syntax. They + are marked as 'java-printf-format' in POT and PO files. + o xgettext now recognizes text blocks as string literals. + - JavaScript: + xgettext parses JSX expressions more reliably. + - Ruby: + o xgettext now supports Ruby. + o 'msgfmt -c' now verifies the syntax of translations of Ruby format + strings. + * Improvements for translators: + - When msgfmt writes a MO file, it now does so in such a way that processes + that are currently using an older copy of the MO file will not crash. + + * Libtextstyle: + - Added support for emitting hyperlinks. + - New API for doing formatted output. + - The example programs support the NO_COLOR environment variable. + +------------------------------------------------------------------- --- /work/SRC/openSUSE:Factory/gettext-runtime/gettext-runtime.changes 2020-07-15 11:11:37.460797204 +0200 +++ /work/SRC/openSUSE:Factory/.gettext-runtime.new.4249/gettext-runtime.changes 2020-10-06 17:06:09.241270429 +0200 @@ -1,0 +2,36 @@ +Fri Aug 7 07:46:39 UTC 2020 - Marketa Calabkova <[email protected]> + +- Add multiple new features (bsc#1165138) +- Add patches: + * 0001-msgcat-Add-feature-to-use-the-newest-po-file.patch + * 0002-msgcat-Merge-headers-when-use-first.patch +- Reintroduce utoreconf call + +------------------------------------------------------------------- +Tue Jul 28 09:33:34 UTC 2020 - Christian Vögl <[email protected]> + +- Update to 0.21: + * Programming languages support: + - Shell: + o xgettext now recognizes and ignores 'env' invocations and environment + variable assignments in front of commands. + - Java: + o xgettext now recognizes format strings in the Formatter syntax. They + are marked as 'java-printf-format' in POT and PO files. + o xgettext now recognizes text blocks as string literals. + - JavaScript: + xgettext parses JSX expressions more reliably. + - Ruby: + o xgettext now supports Ruby. + o 'msgfmt -c' now verifies the syntax of translations of Ruby format + strings. + * Improvements for translators: + - When msgfmt writes a MO file, it now does so in such a way that processes + that are currently using an older copy of the MO file will not crash. + + * Libtextstyle: + - Added support for emitting hyperlinks. + - New API for doing formatted output. + - The example programs support the NO_COLOR environment variable. + +------------------------------------------------------------------- Old: ---- gettext-0.20.2.tar.xz gettext-0.20.2.tar.xz.sig New: ---- 0001-msgcat-Add-feature-to-use-the-newest-po-file.patch 0002-msgcat-Merge-headers-when-use-first.patch gettext-0.21.tar.xz gettext-0.21.tar.xz.sig ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ gettext-csharp.spec ++++++ --- /var/tmp/diff_new_pack.onfuU1/_old 2020-10-06 17:06:10.913271873 +0200 +++ /var/tmp/diff_new_pack.onfuU1/_new 2020-10-06 17:06:10.913271873 +0200 @@ -28,7 +28,7 @@ BuildRequires: tcl Requires: mono URL: http://www.gnu.org/software/gettext/ -Version: 0.20.2 +Version: 0.21 Release: 0 Summary: Native Language Support (NLS) for C# License: LGPL-2.1-or-later ++++++ gettext-java.spec ++++++ --- /var/tmp/diff_new_pack.onfuU1/_old 2020-10-06 17:06:10.937271894 +0200 +++ /var/tmp/diff_new_pack.onfuU1/_new 2020-10-06 17:06:10.941271897 +0200 @@ -17,7 +17,7 @@ Name: gettext-java -Version: 0.20.2 +Version: 0.21 Release: 0 Summary: Java Support for Native Language Support (NLS) License: LGPL-2.1-or-later ++++++ gettext-runtime-mini.spec ++++++ --- /var/tmp/diff_new_pack.onfuU1/_old 2020-10-06 17:06:10.977271929 +0200 +++ /var/tmp/diff_new_pack.onfuU1/_new 2020-10-06 17:06:10.981271932 +0200 @@ -20,9 +20,11 @@ %bcond_without mini Name: gettext-runtime-mini -Version: 0.20.2 +Version: 0.21 Release: 0 +BuildRequires: automake BuildRequires: gcc-c++ +BuildRequires: libtool # To get an updated linkdupes.sh (in case there are new dupes), temproarily enable: #BuildRequires: fdupes %if %{without mini} @@ -70,6 +72,9 @@ Patch11: boo941629-unnessary-rpath-on-standard-path.patch # PATCH-FIX-SUSE Bug boo#1106843 Patch13: reproducible.patch +# PATCH-FEATURE bsc#1165138 +Patch14: 0001-msgcat-Add-feature-to-use-the-newest-po-file.patch +Patch15: 0002-msgcat-Merge-headers-when-use-first.patch %description This package contains the intl library as well as tools that ease the @@ -158,9 +163,13 @@ %patch6 -p1 %patch11 -p1 %patch13 -p1 +%patch14 -p1 +%patch15 -p1 %build %define _lto_cflags %{nil} +# expect a couple "You should update your `aclocal.m4' by running aclocal." +autoreconf -fiv #sh autogen.sh export CFLAGS="%{optflags} -pipe -W -Wall -Dgcc_is_lint" export CXXFLAGS="$CFLAGS -Dgcc_is_lint" ++++++ gettext-runtime.spec ++++++ --- /var/tmp/diff_new_pack.onfuU1/_old 2020-10-06 17:06:11.013271960 +0200 +++ /var/tmp/diff_new_pack.onfuU1/_new 2020-10-06 17:06:11.017271963 +0200 @@ -20,12 +20,14 @@ %bcond_with mini Name: gettext-runtime -Version: 0.20.2 +Version: 0.21 Release: 0 BuildRequires: gcc-c++ +BuildRequires: libtool # To get an updated linkdupes.sh (in case there are new dupes), temproarily enable: #BuildRequires: fdupes %if %{without mini} +BuildRequires: automake BuildRequires: glib2-devel BuildRequires: libcroco-devel BuildRequires: libxml2-devel @@ -70,6 +72,9 @@ Patch11: boo941629-unnessary-rpath-on-standard-path.patch # PATCH-FIX-SUSE Bug boo#1106843 Patch13: reproducible.patch +# PATCH-FEATURE bsc#1165138 +Patch14: 0001-msgcat-Add-feature-to-use-the-newest-po-file.patch +Patch15: 0002-msgcat-Merge-headers-when-use-first.patch %description This package contains the intl library as well as tools that ease the @@ -158,9 +163,13 @@ %patch6 -p1 %patch11 -p1 %patch13 -p1 +%patch14 -p1 +%patch15 -p1 %build %define _lto_cflags %{nil} +# expect a couple "You should update your `aclocal.m4' by running aclocal." +autoreconf -fiv #sh autogen.sh export CFLAGS="%{optflags} -pipe -W -Wall -Dgcc_is_lint" export CXXFLAGS="$CFLAGS -Dgcc_is_lint" ++++++ 0001-msgcat-Add-feature-to-use-the-newest-po-file.patch ++++++ >From a079538e51c6c6e9855d9e7bde1519eaa59bb94d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mark=C3=A9ta=20Cal=C3=A1bkov=C3=A1?= <[email protected]> Date: Thu, 9 Jan 2020 14:40:25 +0100 Subject: [PATCH 1/2] msgcat: Add feature to use the newest po file. When concatenating po files, it is often useful to prefer strings from the newest file regardless their ordering on the command line. --- gettext-tools/src/Makefile.am | 4 +- gettext-tools/src/message.c | 6 +++ gettext-tools/src/message.h | 4 ++ gettext-tools/src/msgcat.c | 10 ++++ gettext-tools/src/msgl-age.c | 96 +++++++++++++++++++++++++++++++++ gettext-tools/src/msgl-age.h | 36 +++++++++++++ gettext-tools/src/msgl-cat.c | 15 ++++++ gettext-tools/src/msgl-cat.h | 1 + gettext-tools/src/msgl-header.c | 47 ++++++++++++++++ gettext-tools/src/msgl-header.h | 6 +++ 10 files changed, 223 insertions(+), 2 deletions(-) create mode 100644 gettext-tools/src/msgl-age.c create mode 100644 gettext-tools/src/msgl-age.h Index: gettext-0.21/gettext-tools/src/Makefile.am =================================================================== --- gettext-0.21.orig/gettext-tools/src/Makefile.am +++ gettext-0.21/gettext-tools/src/Makefile.am @@ -43,7 +43,7 @@ noinst_HEADERS = \ write-catalog.h write-po.h write-properties.h write-stringtable.h \ dir-list.h file-list.h po-gram-gen.h po-gram-gen2.h cldr-plural.h \ cldr-plural-exp.h locating-rule.h its.h search-path.h \ - msgl-charset.h msgl-equal.h msgl-iconv.h msgl-ascii.h msgl-cat.h msgl-header.h \ + msgl-age.h msgl-charset.h msgl-equal.h msgl-iconv.h msgl-ascii.h msgl-cat.h msgl-header.h \ msgl-english.h msgl-check.h msgl-fsearch.h msgfmt.h msgunfmt.h \ plural-count.h plural-eval.h plural-distrib.h \ read-mo.h write-mo.h \ @@ -174,7 +174,7 @@ FORMAT_SOURCE += \ libgettextsrc_la_SOURCES = \ $(COMMON_SOURCE) read-catalog.c \ write-catalog.c write-properties.c write-stringtable.c write-po.c \ -msgl-ascii.c msgl-iconv.c msgl-equal.c msgl-cat.c msgl-header.c msgl-english.c \ +msgl-age.c msgl-ascii.c msgl-iconv.c msgl-equal.c msgl-cat.c msgl-header.c msgl-english.c \ msgl-check.c file-list.c msgl-charset.c po-time.c plural-exp.c plural-eval.c \ plural-table.c quote.h sentence.h sentence.c \ $(FORMAT_SOURCE) \ Index: gettext-0.21/gettext-tools/src/message.c =================================================================== --- gettext-0.21.orig/gettext-tools/src/message.c +++ gettext-0.21/gettext-tools/src/message.c @@ -356,6 +356,12 @@ message_list_append (message_list_ty *ml abort (); } +void +message_list_append_list (message_list_ty *mlp, message_list_ty *mlp2) +{ + for (int i = 0; i < mlp2->nitems; i++) + message_list_append (mlp,mlp2->item[i]); +} void message_list_prepend (message_list_ty *mlp, message_ty *mp) Index: gettext-0.21/gettext-tools/src/message.h =================================================================== --- gettext-0.21.orig/gettext-tools/src/message.h +++ gettext-0.21/gettext-tools/src/message.h @@ -24,6 +24,7 @@ #include "mem-hash-map.h" #include <stdbool.h> +#include <time.h> #ifdef __cplusplus @@ -269,6 +270,8 @@ extern void extern void message_list_append (message_list_ty *mlp, message_ty *mp); extern void + message_list_append_list (message_list_ty *mlp, message_list_ty *mlp2); +extern void message_list_prepend (message_list_ty *mlp, message_ty *mp); extern void message_list_insert_at (message_list_ty *mlp, size_t n, message_ty *mp); @@ -350,6 +353,7 @@ struct msgdomain_list_ty size_t nitems_max; bool use_hashtable; const char *encoding; /* canonicalized encoding or NULL if unknown */ + time_t msgage; }; extern msgdomain_list_ty * Index: gettext-0.21/gettext-tools/src/msgcat.c =================================================================== --- gettext-0.21.orig/gettext-tools/src/msgcat.c +++ gettext-0.21/gettext-tools/src/msgcat.c @@ -88,6 +88,7 @@ static const struct option long_options[ { "to-code", required_argument, NULL, 't' }, { "unique", no_argument, NULL, 'u' }, { "use-first", no_argument, NULL, CHAR_MAX + 1 }, + { "use-newest", no_argument, NULL, CHAR_MAX + 9 }, { "version", no_argument, NULL, 'V' }, { "width", required_argument, NULL, 'w' }, { "more-than", required_argument, NULL, '>' }, @@ -141,6 +142,7 @@ main (int argc, char **argv) more_than = 0; less_than = INT_MAX; use_first = false; + use_newest = false; while ((optchar = getopt_long (argc, argv, "<:>:D:eEf:Fhino:pPst:uVw:", long_options, NULL)) != EOF) @@ -277,6 +279,11 @@ main (int argc, char **argv) message_print_style_filepos (filepos_comment_none); break; + case CHAR_MAX + 9: /* --use-newest */ + use_newest = true; + use_first = true; + break; + default: usage (EXIT_FAILURE); /* NOTREACHED */ @@ -428,6 +435,9 @@ Output details:\n")); --use-first use first available translation for each\n\ message, don't merge several translations\n")); printf (_("\ + --use-newest use the most up-to-date available translation\n\ + for each message, don't merge several translations\n")); + printf (_("\ --lang=CATALOGNAME set 'Language' field in the header entry\n")); printf (_("\ --color use colors and other text attributes always\n\ Index: gettext-0.21/gettext-tools/src/msgl-age.c =================================================================== --- /dev/null +++ gettext-0.21/gettext-tools/src/msgl-age.c @@ -0,0 +1,96 @@ +/* Message list header time simple parser. + Copyright (C) 2019 Free Software Foundation, Inc. + Written by Markéta Calábková <[email protected]>, 2019. + + 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 3 of the License, 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, see <https://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include <string.h> +#include <time.h> + +#include "xalloc.h" +#include "error.h" +#include "xerror.h" +#include "xvasprintf.h" + +#include "msgl-header.h" +#include <stdlib.h> +#include <stdio.h> +#include "gettext.h" + +#include "msgl-age.h" + +#define _(str) gettext (str) + +void +msgdomain_sort_by_ages (msgdomain_list_ty **mdlps, size_t nfiles) +{ + qsort (mdlps, nfiles, sizeof(msgdomain_list_ty*), msgdomain_compare_ages); +} + +int +msgdomain_compare_ages (const void * p1, const void * p2) +{ + if (difftime((*(msgdomain_list_ty **)p2)->msgage, (*(msgdomain_list_ty **)p1)->msgage) > 0) + return 1; + else + return 0; +} + +void +msgdomain_read_ages (msgdomain_list_ty *mdlp) +{ + time_t times[mdlp->nitems]; + const char * field = "PO-Revision-Date:"; + char * where; + + for (int i = 0; i < mdlp->nitems; i++) + { + message_list_ty *mlp = mdlp->item[i]->messages; + + message_list_read_header_field (mlp, field, &where); + } + struct tm tmptm; + char *trail; + memset (&tmptm, 0, sizeof(struct tm)); + if ((trail = strptime (where, "%Y-%m-%d %H:%M:%S%z", &tmptm)) != NULL) + mdlp->msgage = mktime (&tmptm); + else if ((trail = strptime (where, "%Y-%m-%d %H:%M:%S", &tmptm)) != NULL) + mdlp->msgage = mktime (&tmptm); + else if ((trail = strptime (where, "%Y-%m-%d %H:%M%z", &tmptm)) != NULL) + mdlp->msgage = mktime (&tmptm); + else if ((trail = strptime (where, "%Y-%m-%d %H:%M", &tmptm)) != NULL) + mdlp->msgage = mktime (&tmptm); + else + { + /* There is probably no creation date. Assign 0 and throw warning. */ + mdlp->msgage = 0; + multiline_warning (xasprintf (_("warning: ")), + xasprintf (_("\ +PO-Revision-Date has no or invalid value, assuming it is old.\n\ +"))); + return; + } + if ((*trail != '\n') && (*trail != '\0')) + multiline_warning (xasprintf (_("warning: ")), + xasprintf (_("\ +Unknown trailing characters after PO-Revision-Date, ignoring.\n\ +"))); +} + + + Index: gettext-0.21/gettext-tools/src/msgl-age.h =================================================================== --- /dev/null +++ gettext-0.21/gettext-tools/src/msgl-age.h @@ -0,0 +1,36 @@ +/* Message list header time simple parser. + Copyright (C) 2019 Free Software Foundation, Inc. + Written by Markéta Calábková <[email protected]>, 2019. + + 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 3 of the License, 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, see <https://www.gnu.org/licenses/>. */ + +#ifndef _MSGL_AGE_H +#define _MSGL_AGE_H + +#include "message.h" + +/* Helper function to compare the ages, needed by qsort. */ +int + msgdomain_compare_ages (const void *, const void *); + +/* Simple function to modify intern ordering of files + * such that the newer file comes first. In fact it just calls qsort. */ +void + msgdomain_sort_by_ages (msgdomain_list_ty **, size_t); + +/* Parse dates in PO-Revision-Date: and store them inside the structure. */ +void + msgdomain_read_ages (msgdomain_list_ty *); + +#endif Index: gettext-0.21/gettext-tools/src/msgl-cat.c =================================================================== --- gettext-0.21.orig/gettext-tools/src/msgl-cat.c +++ gettext-0.21/gettext-tools/src/msgl-cat.c @@ -37,6 +37,7 @@ #include "message.h" #include "read-catalog.h" #include "po-charset.h" +#include "msgl-age.h" #include "msgl-ascii.h" #include "msgl-equal.h" #include "msgl-iconv.h" @@ -57,6 +58,11 @@ int less_than; If false, merge all available translations into one and fuzzy it. */ bool use_first; +/* If true, sort all the translation according to their age and let + use_first finish the job. + If false, keep the order of translations. */ +bool use_newest; + /* If true, merge like msgcomm. If false, merge like msgcat and msguniq. */ bool msgcomm_mode = false; @@ -123,6 +129,15 @@ catenate_msgdomain_list (string_list_ty for (n = 0; n < nfiles; n++) mdlps[n] = read_catalog_file (files[n], input_syntax); + /* --use-newest case -- sort messages by time and then let --use-first finish the job */ + if (use_newest) + { + for (n = 0; n < nfiles; n++) + msgdomain_read_ages (mdlps[n]); + + msgdomain_sort_by_ages (mdlps, nfiles); + } + /* Determine the canonical name of each input file's encoding. */ canon_charsets = XNMALLOC (nfiles, const char **); for (n = 0; n < nfiles; n++) Index: gettext-0.21/gettext-tools/src/msgl-cat.h =================================================================== --- gettext-0.21.orig/gettext-tools/src/msgl-cat.h +++ gettext-0.21/gettext-tools/src/msgl-cat.h @@ -37,6 +37,7 @@ extern DLL_VARIABLE int less_than; /* If true, use the first available translation. If false, merge all available translations into one and fuzzy it. */ extern DLL_VARIABLE bool use_first; +extern DLL_VARIABLE bool use_newest; /* If true, merge like msgcomm. If false, merge like msgcat and msguniq. */ Index: gettext-0.21/gettext-tools/src/msgl-header.c =================================================================== --- gettext-0.21.orig/gettext-tools/src/msgl-header.c +++ gettext-0.21/gettext-tools/src/msgl-header.c @@ -222,3 +222,50 @@ message_list_delete_header_field (messag } } } + +void +message_list_read_header_field (message_list_ty *mlp, + const char *field, char **where_ptr) +{ + size_t field_len = strlen (field); + size_t j; + + /* Search the header entry. */ + for (j = 0; j < mlp->nitems; j++) + if (is_header (mlp->item[j]) && !mlp->item[j]->obsolete) + { + /* We found the correct message. */ + message_ty *mp = mlp->item[j]; + + /* Tag the header entry. */ + const char *header = mp->msgstr; + + /* Test whether the field occurs in the header entry. */ + const char *h; + + for (h = header; *h != '\0'; ) + { + if (strncmp (h, field, field_len) == 0) + break; + /* Jump by lines. */ + h = strchr (h, '\n'); + if (h == NULL) + break; + h++; + } + if (h != NULL && *h != '\0') + { + /* We found it and it is nonempty. Read the value of the field. */ + h += field_len + 1; + char *enh = strchr (h, '\n'); + if (enh != NULL && *enh != '\0') + { + *where_ptr = (char *)XNMALLOC (((enh - h) + 1), char); + memcpy (*where_ptr, h, enh - h); + /* Make the string null-terminated. */ + (*where_ptr)[enh-h] = '\0'; + } + } + } +} + Index: gettext-0.21/gettext-tools/src/msgl-header.h =================================================================== --- gettext-0.21.orig/gettext-tools/src/msgl-header.h +++ gettext-0.21/gettext-tools/src/msgl-header.h @@ -40,6 +40,12 @@ extern void message_list_delete_header_field (message_list_ty *mlp, const char *field); +/* Read the given field from the header. + The FIELD name ends in a colon. */ +extern void + message_list_read_header_field (message_list_ty *mlp, + const char *field, char **where_ptr); + #ifdef __cplusplus } ++++++ 0002-msgcat-Merge-headers-when-use-first.patch ++++++ >From df4aef6209615bdd44cd45208acfe7367451a8fe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mark=C3=A9ta=20Cal=C3=A1bkov=C3=A1?= <[email protected]> Date: Thu, 9 Jan 2020 14:45:49 +0100 Subject: [PATCH 2/2] msgcat: Merge headers when --use-first Merging headers line by line is especially useful when one header line is present only in the second file. For example when Plural-Forms: is present only in the second file, msgcat could create an invalid output file. We also return error when Plural-Forms: values do not match. --- gettext-tools/src/message.c | 2 - gettext-tools/src/msgl-cat.c | 5 ++ gettext-tools/src/msgl-header.c | 155 +++++++++++++++++++++++++++++--- gettext-tools/src/msgl-header.h | 8 ++ 4 files changed, 157 insertions(+), 13 deletions(-) Index: gettext-0.20.1/gettext-tools/src/message.c =================================================================== --- gettext-0.20.1.orig/gettext-tools/src/message.c +++ gettext-0.20.1/gettext-tools/src/message.c @@ -411,7 +411,6 @@ message_list_insert_at (message_list_ty } -#if 0 /* unused */ void message_list_delete_nth (message_list_ty *mlp, size_t n) { @@ -431,7 +430,6 @@ message_list_delete_nth (message_list_ty mlp->use_hashtable = false; } } -#endif void Index: gettext-0.20.1/gettext-tools/src/msgl-cat.c =================================================================== --- gettext-0.20.1.orig/gettext-tools/src/msgl-cat.c +++ gettext-0.20.1/gettext-tools/src/msgl-cat.c @@ -40,6 +40,7 @@ #include "msgl-age.h" #include "msgl-ascii.h" #include "msgl-equal.h" +#include "msgl-header.h" #include "msgl-iconv.h" #include "xalloc.h" #include "xmalloca.h" @@ -286,6 +287,10 @@ catenate_msgdomain_list (string_list_ty } } + /* Merge headers, please. */ + if (use_first) + msgdomain_lists_merge_headers (mdlps, nfiles); + /* Create list of resulting messages, but don't fill it. Only count the number of translations for each message. If for a message, there is at least one non-fuzzy, non-empty translation, Index: gettext-0.20.1/gettext-tools/src/msgl-header.c =================================================================== --- gettext-0.20.1.orig/gettext-tools/src/msgl-header.c +++ gettext-0.20.1/gettext-tools/src/msgl-header.c @@ -26,9 +26,12 @@ #include <string.h> #include "xalloc.h" +#include "xerror.h" +#include "xvasprintf.h" +#include "gettext.h" #define SIZEOF(a) (sizeof(a) / sizeof(a[0])) - +#define _(str) gettext (str) /* The known fields in their usual order. */ static const struct @@ -50,6 +53,98 @@ known_fields[] = { "Content-Transfer-Encoding:", sizeof ("Content-Transfer-Encoding:") - 1 } }; +void +msgdomain_lists_merge_headers (msgdomain_list_ty **mdlps, + size_t nfiles) +{ + message_list_list_ty * headers = message_list_list_alloc (); + char * plur = "Plural-Forms:"; + char * plurals[nfiles]; + int plur_index = 0; + /* First, find all header entries and cut them to lines. */ + for (int n = 0; n < nfiles; n++) + { + msgdomain_list_ty *mdlp = mdlps[n]; + for (size_t k = 0; k < mdlp->nitems; k++) + { + message_list_ty * chopped = message_list_header_list (mdlp->item[k]->messages); + if (chopped) message_list_list_append (headers, chopped); + } + + /* Set plural to NULL by default. */ + plurals[n] = NULL; + } + /* While there are some messages remaining, take the first one. */ + while (headers->nitems > 0) + { + message_ty * field = headers->item[0]->item[0]; + /* Let us save plurals for later use. */ + if (strcmp(field->msgid, plur) == 0) + { + plurals[0] = XNMALLOC (field->msgstr_len+1, char); + strcpy (plurals[0], field->msgstr); + for (int i = 1; i < headers->nitems; i++) + { + message_ty * mp = message_list_search (headers->item[i], NULL, plur); + if (mp!=NULL) + { + plurals[i] = XNMALLOC (mp->msgstr_len+1, char); + strcpy (plurals[i], mp->msgstr); + } + } + } + /* Set the header field and delete all the occurences of the field. */ + msgdomain_list_set_header_field (mdlps[0], field->msgid, field->msgstr); + for (int i = 1; i < headers->nitems; i++) + { + message_ty * mp = message_list_search (headers->item[i], NULL, field->msgid); + if (mp != NULL) + { + /* If needed, fix line numbering in advance. */ + if (mp != headers->item[i]->item[0]) + for (int l = mp->pos.line_number - headers->item[i]->item[0]->pos.line_number + 1; l < headers->item[i]->nitems; l++) + headers->item[i]->item[l]->pos.line_number--; + message_list_delete_nth (headers->item[i], mp->pos.line_number - headers->item[i]->item[0]->pos.line_number); + } + } + message_list_delete_nth (headers->item[0], 0); + /* If the first header is empty, start to process next nonempty header. */ + while (headers->nitems > 0 && headers->item[0]->nitems == 0) + { + message_list_free (headers->item[0], 0); + for (int i = 0; i < headers->nitems - 1; i++) + headers->item[i] = headers->item[i+1]; + headers->nitems--; + } + } + + /* Some plural manipulation. */ + char *res = NULL; + char *prevres = NULL; + prevres = plurals[0]; + /* The prevres is the value currently in the output header, + * res is the value just read. So if res == NULL we just + * continue, which is correct. */ + for (int n = 1; n < nfiles; n++) + { + res = plurals[n]; + if (res != NULL) + { + if (prevres == NULL) + { + msgdomain_list_set_header_field (mdlps[0], plur, res); + prevres = res; + } + else if (strcmp (res, prevres) != 0) + { + multiline_error (xstrdup (""), + xasprintf (_("\ +Input po files have different Plural-Forms. Invalid output file was created. \n\ +Please, fix the plurals.\n"))); + } + } + } +} void msgdomain_list_set_header_field (msgdomain_list_ty *mdlp, @@ -81,8 +176,8 @@ msgdomain_list_set_header_field (msgdoma { message_ty *mp = mlp->item[j]; - /* Modify the header entry. */ - const char *header = mp->msgstr; + /* Modify the header entry (it does not have to be present). */ + const char *header = (mp->msgstr != NULL) ? mp->msgstr : "\0"; char *new_header = XNMALLOC (strlen (header) + 1 + strlen (field) + 1 + strlen (value) + 1 + 1, @@ -230,14 +325,14 @@ message_list_read_header_field (message_ size_t field_len = strlen (field); size_t j; + *where_ptr = NULL; + /* Search the header entry. */ for (j = 0; j < mlp->nitems; j++) if (is_header (mlp->item[j]) && !mlp->item[j]->obsolete) { - /* We found the correct message. */ + /* We found the correct message. */ message_ty *mp = mlp->item[j]; - - /* Tag the header entry. */ const char *header = mp->msgstr; /* Test whether the field occurs in the header entry. */ @@ -247,7 +342,7 @@ message_list_read_header_field (message_ { if (strncmp (h, field, field_len) == 0) break; - /* Jump by lines. */ + /* Jump by lines. */ h = strchr (h, '\n'); if (h == NULL) break; @@ -257,15 +352,57 @@ message_list_read_header_field (message_ { /* We found it and it is nonempty. Read the value of the field. */ h += field_len + 1; - char *enh = strchr (h, '\n'); - if (enh != NULL && *enh != '\0') + char *enh = strchr (h, '\n'); + if (enh != NULL && *enh != '\0') { *where_ptr = (char *)XNMALLOC (((enh - h) + 1), char); memcpy (*where_ptr, h, enh - h); - /* Make the string null-terminated. */ + /* Make the string null-terminated. */ (*where_ptr)[enh-h] = '\0'; - } + } } } } +message_list_ty * +message_list_header_list (message_list_ty *mlp) +{ + size_t j; + + /* Search the header entry. */ + for (j = 0; j < mlp->nitems; j++) + if (is_header (mlp->item[j]) && !mlp->item[j]->obsolete) + { + /* We found the correct message. */ + message_ty *mp = mlp->item[j]; + const char *h = mp->msgstr; + message_list_ty * header = message_list_alloc (false); + int ctr = 0; + + while (*h != '\0') + { + char *enh = strchr (h, ':'); + enh++; + char * msgid = (char *)XNMALLOC (((enh - h) + 1), char); + memcpy (msgid, h, enh - h); + /* Make the string null-terminated. */ + (msgid)[enh-h] = '\0'; + h = enh + 1; + + enh = strchr (h, '\n'); + if (enh != NULL) + { + char * msgstr = (char *)XNMALLOC (((enh - h) + 1), char); + memcpy (msgstr, h, enh - h); + /* Make the string null-terminated. */ + msgstr[enh-h] = '\0'; + lex_pos_ty pos = {NULL, ctr++}; + message_list_append (header, message_alloc (NULL, msgid, NULL, msgstr, enh - h, &pos)); + h = enh + 1; + } + else return NULL; + } + return header; + } + return NULL; +} Index: gettext-0.20.1/gettext-tools/src/msgl-header.h =================================================================== --- gettext-0.20.1.orig/gettext-tools/src/msgl-header.h +++ gettext-0.20.1/gettext-tools/src/msgl-header.h @@ -33,6 +33,11 @@ extern "C" { extern void msgdomain_list_set_header_field (msgdomain_list_ty *mdlp, const char *field, const char *value); +/* Merge headers of po files. + */ +extern void + msgdomain_lists_merge_headers (msgdomain_list_ty **mdlps, + size_t nfiles); /* Remove the given field from the header. The FIELD name ends in a colon. */ @@ -46,6 +51,9 @@ extern void message_list_read_header_field (message_list_ty *mlp, const char *field, char **where_ptr); +/* List all the headers from a po file. */ +extern message_list_ty * + message_list_header_list (message_list_ty *mlp); #ifdef __cplusplus } ++++++ gettext-0.20.2.tar.xz -> gettext-0.21.tar.xz ++++++ /work/SRC/openSUSE:Factory/gettext-runtime/gettext-0.20.2.tar.xz /work/SRC/openSUSE:Factory/.gettext-runtime.new.4249/gettext-0.21.tar.xz differ: char 26, line 1 ++++++ gettext-0.20.2.tar.xz.sig -> gettext-0.21.tar.xz.sig ++++++ --- /work/SRC/openSUSE:Factory/gettext-runtime/gettext-0.20.2.tar.xz.sig 2020-05-11 13:25:33.187130251 +0200 +++ /work/SRC/openSUSE:Factory/.gettext-runtime.new.4249/gettext-0.21.tar.xz.sig 2020-10-06 17:06:01.265263540 +0200 @@ -1,17 +1,17 @@ -----BEGIN PGP SIGNATURE----- Version: GnuPG v2 -iQIcBAABCAAGBQJelYUvAAoJEPW+iyZ8akBtVTkP/R/mGzw/Pacu39DlJlCoUUfi -FO1eSEOzCffCQSSXah6myZqNYQF3HkBJvjfm1u9/FME5dvn1p+r4g3ko06v0a8KH -V6ByKCwdJo06TlsWgizN9idVxkonG5yYXkoJpw7yEksvXYrHieEah/YYhfQVB/N7 -rRB5SQgfpu+Uy51h/istslO6UF1GdbpMwPubyARg2EDWtkX0HQ0N4xq3RAHUz37S -nlbr2j/+D8u0EocQtFeeog5EugYBnLlbtEpunIUKML3QFRf6VDU3ChOeplKuStwS -iJIGlhaX4WGsbW431DAWar8gr8xp5t1OUhtp/FapG6Cdk5D0QerH7RJSFj01RFPq -EfHfTAuJi9oyzpNkAwCD92IaPd3ZRIjr9WkW+Y/QLE7yHXiLVOXRWI1colZBFyUr -gukuQ72g+E6VZYZdCult9UrGA+yc0ppGJhFu9eOaL2e4ScWb54+NuUkxwGNUEdj3 -kxGLofiQKJkvOeSGe6oMl8Rc96lCO1Z8pLwT6aRlj1vMOoIFfehZtFFRvesgpt7G -Jp7GhK2XXxJUqfMT6D2+J0Fp7CPe5buc/ak/x/lgfhI24/YmJuDs/OiiONh+3bPO -VIstn9yrITAbdCvIqaHu6ltB6exCArThtMVovYkaKgBQrGDUh9kgdr7HHen99lTd -QhtpcFSzd+eshh8ELDW+ -=5tvt +iQIcBAABCAAGBQJfHh9mAAoJEPW+iyZ8akBtIXIQAKGUlp67181VBHA050f8pcxX +QHnQbna51vvUI/5zwO5gOJb/ocVBsrXM0wfBUmnSOVH+vKw2CGOil9QfmhTVEWNN +R4DBiFs3hMefabzdp177vWn6gBWYVZ10hQy/ptx4kaNEFHHaXo+ei0p0nfkpab5D +0cNniOCm35tkK0WeFgPESQeGpmItWXRsSkg+xeZblm1DJ4gbQYqCPgFJSYVZzq6G +PEfyISC1OAll8o0dz8D2nddkiVboBMaurXpuMt7CVCCjiEUWGyWiEdfhxBI/aE+z +bZ7hVCV2dThoFvz3ay90IjisjBhsNGQ9cEEB+hyvCfCX0c93OnAuD35nBvb4RfFK +Be1rFqp0SN7ZkeHp4djdDoze34ui0SHWRpzNjD7Hf/mz3SyxzuY6t7sPL1YObz8i +dlCXJ8uYoG9ZU74eDK9epVb880hOPL6G1NVqX859wS14vPH/IGIC7W+BYPBcYsSJ +InxaD2CU38iBrhNS6s8Y9hXjnTqyWWQ4e1yRl1m76MpSXDDwEUzTv2isyPlSJst6 +341V2TPAesXJzB/ndMcusUM2gK+63cH1VSByLn1FYB+InFxKzyUTP6JNqv3eECV8 +WTLD5RIccp391fuGtbIfccVVucOZhahzCxvouXGjQTmT6t28p72oCvroUySkvgoe +6en2/1+QyIzFLJqLCKBq +=02/q -----END PGP SIGNATURE-----
