bug-gettext
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[bug-gettext] [PATCH] msgcat: Add feature to use the newest po file.


From: Marketa Calabkova
Subject: [bug-gettext] [PATCH] msgcat: Add feature to use the newest po file.
Date: Tue, 22 Oct 2019 19:30:33 +0200
User-agent: Mozilla/5.0 (X11; Linux x86_64; rv:68.0) Gecko/20100101 Thunderbird/68.1.1

When concatenating po files, it is often useful to prefer strings from
the newest file regardlees their ordering on the command line.
---
 gettext-tools/src/Makefile.am   |  4 +-
 gettext-tools/src/message.c     |  6 +++
 gettext-tools/src/message.h     |  2 +
 gettext-tools/src/msgcat.c      | 10 ++++
 gettext-tools/src/msgl-age.c    | 82 +++++++++++++++++++++++++++++++++
 gettext-tools/src/msgl-age.h    | 27 +++++++++++
 gettext-tools/src/msgl-cat.c    | 15 ++++++
 gettext-tools/src/msgl-cat.h    |  1 +
 gettext-tools/src/msgl-header.c | 46 ++++++++++++++++++
 gettext-tools/src/msgl-header.h |  6 +++
 10 files changed, 197 insertions(+), 2 deletions(-)
 create mode 100644 gettext-tools/src/msgl-age.c
 create mode 100644 gettext-tools/src/msgl-age.h

diff --git a/gettext-tools/src/Makefile.am b/gettext-tools/src/Makefile.am
index b0894211d..eb4fd4272 100644
--- a/gettext-tools/src/Makefile.am
+++ b/gettext-tools/src/Makefile.am
@@ -42,7 +42,7 @@ str-list.h \
 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 \
@@ -152,7 +152,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) \
diff --git a/gettext-tools/src/message.c b/gettext-tools/src/message.c
index 05437eb15..fa7f4e244 100644
--- a/gettext-tools/src/message.c
+++ b/gettext-tools/src/message.c
@@ -354,6 +354,12 @@ message_list_append (message_list_ty *mlp,
message_ty *mp)
       abort ();
 }
 
+void
+message_list_append_list (message_list_ty *res, message_list_ty *src)
+{
+    for (int i = 0; i < src->nitems; i++)
+        message_list_append(res,src->item[i]);
+}
 
 void
 message_list_prepend (message_list_ty *mlp, message_ty *mp)
diff --git a/gettext-tools/src/message.h b/gettext-tools/src/message.h
index 5ee97187c..818aeaeb1 100644
--- a/gettext-tools/src/message.h
+++ b/gettext-tools/src/message.h
@@ -24,6 +24,7 @@
 #include "hash.h"
 
 #include <stdbool.h>
+#include <time.h>
 
 
 #ifdef __cplusplus
@@ -349,6 +350,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 *
diff --git a/gettext-tools/src/msgcat.c b/gettext-tools/src/msgcat.c
index 831d48739..c8b0d54a5 100644
--- a/gettext-tools/src/msgcat.c
+++ b/gettext-tools/src/msgcat.c
@@ -87,6 +87,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, '>' },
@@ -144,6 +145,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)
@@ -280,6 +282,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 */
@@ -430,6 +437,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\
diff --git a/gettext-tools/src/msgl-age.c b/gettext-tools/src/msgl-age.c
new file mode 100644
index 000000000..c283b10b4
--- /dev/null
+++ b/gettext-tools/src/msgl-age.c
@@ -0,0 +1,82 @@
+/* Message list header time simple parser.
+   Copyright (C) 2019 Free Software Foundation, Inc.
+   Written by Markéta Calábková <address@hidden>, 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
+
+#define _XOPEN_SOURCE
+#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)
+{
+    //oh, ok, let's sort pointers to msgdomains
+    qsort(mdlps, nfiles, sizeof(msgdomain_list_ty*),
msgdomain_compare_ages);
+
+}
+
+int msgdomain_compare_ages(const void * p1, const void * p2)
+{
+    return (*(msgdomain_list_ty **)p2)->msgage - (*(msgdomain_list_ty
**)p1)->msgage;
+}
+
+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;
+  memset(&tmptm, 0, sizeof(struct tm));
+  if(strptime(where,"%Y-%m-%d %H:%M%z", &tmptm) != NULL)
+    mdlp->msgage=mktime(&tmptm);
+  else if(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\
+")));
+  }
+}
+
+
+
diff --git a/gettext-tools/src/msgl-age.h b/gettext-tools/src/msgl-age.h
new file mode 100644
index 000000000..7e2af2a10
--- /dev/null
+++ b/gettext-tools/src/msgl-age.h
@@ -0,0 +1,27 @@
+/* Message list header time simple parser.
+   Copyright (C) 2019 Free Software Foundation, Inc.
+   Written by Markéta Calábková <address@hidden>, 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"
+
+int msgdomain_compare_ages(const void *, const void *);
+void msgdomain_sort_by_ages(msgdomain_list_ty **, size_t);
+void msgdomain_read_ages(msgdomain_list_ty *);
+
+#endif
diff --git a/gettext-tools/src/msgl-cat.c b/gettext-tools/src/msgl-cat.c
index 2e806497c..300949b7e 100644
--- a/gettext-tools/src/msgl-cat.c
+++ b/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 *file_list,
   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++)
diff --git a/gettext-tools/src/msgl-cat.h b/gettext-tools/src/msgl-cat.h
index 878fa0558..811244fa1 100644
--- a/gettext-tools/src/msgl-cat.h
+++ b/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.  */
diff --git a/gettext-tools/src/msgl-header.c
b/gettext-tools/src/msgl-header.c
index c7eaa21a2..c184781db 100644
--- a/gettext-tools/src/msgl-header.c
+++ b/gettext-tools/src/msgl-header.c
@@ -222,3 +222,49 @@ message_list_delete_header_field (message_list_ty *mlp,
           }
       }
 }
+
+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';
+        }
+          }
+      }
+}
+
diff --git a/gettext-tools/src/msgl-header.h
b/gettext-tools/src/msgl-header.h
index 9e50b8bd6..3c3357978 100644
--- a/gettext-tools/src/msgl-header.h
+++ b/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
 }
-- 
2.23.0




reply via email to

[Prev in Thread] Current Thread [Next in Thread]