]> git.ipfire.org Git - thirdparty/gettext.git/commitdiff
New msgmerge option --update.
authorBruno Haible <bruno@clisp.org>
Mon, 22 Oct 2001 08:45:29 +0000 (08:45 +0000)
committerBruno Haible <bruno@clisp.org>
Mon, 22 Oct 2001 08:45:29 +0000 (08:45 +0000)
src/ChangeLog
src/Makefile.am
src/msgl-equal.c [new file with mode: 0644]
src/msgl-equal.h [new file with mode: 0644]
src/msgmerge.c

index fac6b35abc0cdc6c6dd0e57ba5403c0d42a56695..e6180713af7e5ff85fe19b3b46778683465f9779 100644 (file)
@@ -1,3 +1,21 @@
+2001-09-18  Bruno Haible  <haible@clisp.cons.org>
+
+       * msgl-equal.h: New file.
+       * msgl-equal.c: New file.
+       * msgmerge.c: Include msgl-equal.h, backupfile.h, copy-file.h.
+       (update_mode, version_control_string, backup_suffix_string): New
+       variables.
+       (long_options): Add --backup, --suffix, --update.
+       (main): Accept options --backup, --suffix, -U/--update. If in update
+       mode, compare old and new message lists, backup the def.po file, and
+       overwrite the def.po file.
+       (usage): Document --backup, --suffix, -U/--update.
+       (DOT_FREQUENCY): Renamed from DOT_FREQUENCE.
+       (merge): Also return def.po message list. Don't share messages between
+       def and result; copy instead.
+       * Makefile.am (noinst_HEADERS): Add msgl-equal.h.
+       (msgmerge_SOURCES): Add msgl-equal.c.
+
 2001-09-19  Bruno Haible  <haible@clisp.cons.org>
 
        * po-hash-gen.y (number): Change type from 'int' to 'size_t'.
index 5ea14dc7f3faccfc95523185378a8150506ed98d..2a423636b11176e1630d26b84aac282785b12486 100644 (file)
@@ -25,9 +25,9 @@ msgattrib msgcat msgcomm msgconv msgen msgexec msggrep msguniq
 
 noinst_HEADERS = pos.h message.h po-gram.h po-hash.h po-charset.h po-lex.h \
 po.h open-po.h read-po.h str-list.h write-po.h dir-list.h file-list.h \
-po-gram-gen.h po-hash-gen.h msgl-charset.h msgl-iconv.h msgl-ascii.h \
-msgl-cat.h msgfmt.h read-mo.h write-mo.h xgettext.h x-c.h x-po.h x-java.h \
-x-ycp.h x-rst.h
+po-gram-gen.h po-hash-gen.h msgl-charset.h msgl-equal.h msgl-iconv.h \
+msgl-ascii.h msgl-cat.h msgfmt.h read-mo.h write-mo.h xgettext.h x-c.h x-po.h \
+x-java.h x-ycp.h x-rst.h
 
 EXTRA_DIST = FILES
 
@@ -67,7 +67,7 @@ gettext_SOURCES = gettext.c
 ngettext_SOURCES = ngettext.c
 msgcmp_SOURCES    = msgcmp.c    $(COMMON_SOURCES)
 msgfmt_SOURCES    = msgfmt.c    $(COMMON_SOURCES) msgl-ascii.c msgl-iconv.c write-mo.c write-java.c plural.c $(FORMAT_SOURCES)
-msgmerge_SOURCES  = msgmerge.c  $(COMMON_SOURCES) msgl-ascii.c write-po.c read-po.c
+msgmerge_SOURCES  = msgmerge.c  $(COMMON_SOURCES) msgl-ascii.c write-po.c read-po.c msgl-equal.c
 msgunfmt_SOURCES  = msgunfmt.c  $(COMMON_SOURCES) msgl-ascii.c write-po.c read-po.c read-mo.c read-java.c
 xgettext_SOURCES  = xgettext.c  $(COMMON_SOURCES) msgl-ascii.c write-po.c file-list.c x-c.c x-po.c x-java.l x-ycp.c x-rst.c $(FORMAT_SOURCES)
 msgattrib_SOURCES = msgattrib.c $(COMMON_SOURCES) msgl-ascii.c write-po.c read-po.c
diff --git a/src/msgl-equal.c b/src/msgl-equal.c
new file mode 100644 (file)
index 0000000..4c827ec
--- /dev/null
@@ -0,0 +1,157 @@
+/* Message list test for equality.
+   Copyright (C) 2001 Free Software Foundation, Inc.
+   Written by Bruno Haible <haible@clisp.cons.org>, 2001.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2, or (at your option)
+   any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software Foundation,
+   Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
+
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+/* Specification.  */
+#include "msgl-equal.h"
+
+
+/* Prototypes for local functions.  Needed to ensure compiler checking of
+   function argument counts despite of K&R C function definition syntax.  */
+static inline bool pos_equal PARAMS ((const lex_pos_ty *pos1,
+                                     const lex_pos_ty *pos2));
+static inline bool string_list_equal PARAMS ((const string_list_ty *slp1,
+                                             const string_list_ty *slp2));
+static inline bool msgdomain_equal PARAMS ((const msgdomain_ty *mdp1,
+                                           const msgdomain_ty *mdp2));
+
+
+static inline bool
+pos_equal (pos1, pos2)
+     const lex_pos_ty *pos1;
+     const lex_pos_ty *pos2;
+{
+  return ((pos1->file_name == pos2->file_name
+          || strcmp (pos1->file_name, pos2->file_name) == 0)
+         && pos1->line_number == pos2->line_number);
+}
+
+static inline bool
+string_list_equal (slp1, slp2)
+     const string_list_ty *slp1;
+     const string_list_ty *slp2;
+{
+  size_t i, i1, i2;
+
+  i1 = (slp1 != NULL ? slp1->nitems : 0);
+  i2 = (slp2 != NULL ? slp2->nitems : 0);
+  if (i1 != i2)
+    return false;
+  for (i = 0; i < i1; i++)
+    if (strcmp (slp1->item[i], slp2->item[i]) != 0)
+      return false;
+  return true;
+}
+
+bool
+message_equal (mp1, mp2)
+     const message_ty *mp1;
+     const message_ty *mp2;
+{
+  size_t i, i1, i2;
+
+  if (strcmp (mp1->msgid, mp2->msgid) != 0)
+    return false;
+
+  if (!(mp1->msgid_plural != NULL
+       ? mp2->msgid_plural != NULL
+         && strcmp (mp1->msgid_plural, mp2->msgid_plural) == 0
+       : mp2->msgid_plural == NULL))
+    return false;
+
+  if (mp1->msgstr_len != mp2->msgstr_len)
+    return false;
+  if (memcmp (mp1->msgstr, mp2->msgstr, mp1->msgstr_len) != 0)
+    return false;
+
+  if (!pos_equal (&mp1->pos, &mp2->pos))
+    return false;
+
+  if (!string_list_equal (mp1->comment, mp2->comment))
+    return false;
+
+  if (!string_list_equal (mp1->comment_dot, mp2->comment_dot))
+    return false;
+
+  i1 = mp1->filepos_count;
+  i2 = mp2->filepos_count;
+  if (i1 != i2)
+    return false;
+  for (i = 0; i < i1; i++)
+    if (!pos_equal (&mp1->filepos[i], &mp2->filepos[i]))
+      return false;
+
+  if (mp1->is_fuzzy != mp2->is_fuzzy)
+    return false;
+
+  for (i = 0; i < NFORMATS; i++)
+    if (mp1->is_format[i] != mp2->is_format[i])
+      return false;
+
+  if (mp1->obsolete != mp2->obsolete)
+    return false;
+
+  return true;
+}
+
+bool
+message_list_equal (mlp1, mlp2)
+     const message_list_ty *mlp1;
+     const message_list_ty *mlp2;
+{
+  size_t i, i1, i2;
+
+  i1 = mlp1->nitems;
+  i2 = mlp2->nitems;
+  if (i1 != i2)
+    return false;
+  for (i = 0; i < i1; i++)
+    if (!message_equal (mlp1->item[i], mlp2->item[i]))
+      return false;
+  return true;
+}
+
+static inline bool
+msgdomain_equal (mdp1, mdp2)
+     const msgdomain_ty *mdp1;
+     const msgdomain_ty *mdp2;
+{
+  return (strcmp (mdp1->domain, mdp2->domain) == 0
+         && message_list_equal (mdp1->messages, mdp2->messages));
+}
+
+bool
+msgdomain_list_equal (mdlp1, mdlp2)
+     const msgdomain_list_ty *mdlp1;
+     const msgdomain_list_ty *mdlp2;
+{
+  size_t i, i1, i2;
+
+  i1 = mdlp1->nitems;
+  i2 = mdlp2->nitems;
+  if (i1 != i2)
+    return false;
+  for (i = 0; i < i1; i++)
+    if (!msgdomain_equal (mdlp1->item[i], mdlp2->item[i]))
+      return false;
+  return true;
+}
diff --git a/src/msgl-equal.h b/src/msgl-equal.h
new file mode 100644 (file)
index 0000000..9953f97
--- /dev/null
@@ -0,0 +1,38 @@
+/* Message list test for equality.
+   Copyright (C) 2001 Free Software Foundation, Inc.
+   Written by Bruno Haible <haible@clisp.cons.org>, 2001.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2, or (at your option)
+   any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software Foundation,
+   Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
+
+#ifndef _MSGL_EQUAL_H
+#define _MSGL_EQUAL_H
+
+#include "message.h"
+
+#include <stdbool.h>
+
+/* Test whether the written representation of two messages / message lists
+   would be the same.  */
+
+extern bool
+       message_equal PARAMS ((const message_ty *mp1, const message_ty *mp2));
+extern bool
+       message_list_equal PARAMS ((const message_list_ty *mlp1,
+                                  const message_list_ty *mlp2));
+extern bool
+       msgdomain_list_equal PARAMS ((const msgdomain_list_ty *mdlp1,
+                                    const msgdomain_list_ty *mdlp2));
+
+#endif /* _MSGL_EQUAL_H */
index ca9f547b8e5f342329714cb7e5d616812d4ac872..7a6b2fcf54b102280ffc9eda3948257981e38920 100644 (file)
 #include "read-po.h"
 #include "write-po.h"
 #include "system.h"
-#include "libgettext.h"
 #include "po.h"
+#include "msgl-equal.h"
+#include "backupfile.h"
+#include "copy-file.h"
+#include "libgettext.h"
 
 #define _(str) gettext (str)
 
@@ -55,10 +58,16 @@ static bool multi_domain_mode = false;
 /* List of user-specified compendiums.  */
 static message_list_list_ty *compendiums;
 
+/* Update mode.  */
+static bool update_mode = false;
+static const char *version_control_string;
+static const char *backup_suffix_string;
+
 /* Long options.  */
 static const struct option long_options[] =
 {
   { "add-location", no_argument, &line_comment, 1 },
+  { "backup", required_argument, NULL, CHAR_MAX + 1 },
   { "compendium", required_argument, NULL, 'C', },
   { "directory", required_argument, NULL, 'D' },
   { "escape", no_argument, NULL, 'E' },
@@ -73,7 +82,9 @@ static const struct option long_options[] =
   { "sort-by-file", no_argument, NULL, 'F' },
   { "sort-output", no_argument, NULL, 's' },
   { "silent", no_argument, NULL, 'q' },
-  { "strict", no_argument, NULL, 'S' },
+  { "strict", no_argument, NULL, CHAR_MAX + 2 },
+  { "suffix", required_argument, NULL, CHAR_MAX + 3 },
+  { "update", no_argument, NULL, 'U' },
   { "verbose", no_argument, NULL, 'v' },
   { "version", no_argument, NULL, 'V' },
   { "width", required_argument, NULL, 'w', },
@@ -93,13 +104,14 @@ struct statistics
 /* Prototypes for local functions.  Needed to ensure compiler checking of
    function argument counts despite of K&R C function definition syntax.  */
 static void usage PARAMS ((int status));
-static msgdomain_list_ty *merge PARAMS ((const char *fn1, const char *fn2));
 static void compendium PARAMS ((const char *filename));
 static void match_domain PARAMS ((const char *fn1, const char *fn2,
                                  message_list_list_ty *definitions,
                                  message_list_ty *refmlp,
                                  message_list_ty *resultmlp,
                                  struct statistics *stats, int *processed));
+static msgdomain_list_ty *merge PARAMS ((const char *fn1, const char *fn2,
+                                        msgdomain_list_ty **defp));
 
 
 int
@@ -111,6 +123,7 @@ main (argc, argv)
   bool do_help;
   bool do_version;
   char *output_file;
+  msgdomain_list_ty *def;
   msgdomain_list_ty *result;
   bool sort_by_filepos = false;
   bool sort_by_msgid = false;
@@ -137,7 +150,7 @@ main (argc, argv)
   output_file = NULL;
 
   while ((opt
-         = getopt_long (argc, argv, "C:D:eEFhimo:qsvVw:", long_options, NULL))
+         = getopt_long (argc, argv, "C:D:eEFhimo:qsUvVw:", long_options, NULL))
         != EOF)
     switch (opt)
       {
@@ -188,8 +201,8 @@ main (argc, argv)
         sort_by_msgid = true;
         break;
 
-      case 'S':
-       message_print_style_uniforum ();
+      case 'U':
+       update_mode = true;
        break;
 
       case 'v':
@@ -210,6 +223,18 @@ main (argc, argv)
        }
        break;
 
+      case CHAR_MAX + 1: /* --backup */
+       version_control_string = optarg;
+       break;
+
+      case CHAR_MAX + 2: /* --strict */
+       message_print_style_uniforum ();
+       break;
+
+      case CHAR_MAX + 3: /* --suffix */
+       backup_suffix_string = optarg;
+       break;
+
       default:
        usage (EXIT_FAILURE);
        break;
@@ -246,6 +271,30 @@ warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\
     }
 
   /* Verify selected options.  */
+  if (update_mode)
+    {
+      if (output_file != NULL)
+       {
+         error (EXIT_FAILURE, 0, _("%s and %s are mutually exclusive"),
+                "--update", "--output-file");
+       }
+    }
+  else
+    {
+      if (version_control_string != NULL)
+       {
+         error (EXIT_SUCCESS, 0, _("%s is only valid with %s"),
+                "--backup", "--update");
+         usage (EXIT_FAILURE);
+       }
+      if (backup_suffix_string != NULL)
+       {
+         error (EXIT_SUCCESS, 0, _("%s is only valid with %s"),
+                "--suffix", "--update");
+         usage (EXIT_FAILURE);
+       }
+    }
+
   if (!line_comment && sort_by_filepos)
     error (EXIT_FAILURE, 0, _("%s and %s are mutually exclusive"),
           "--no-location", "--sort-by-file");
@@ -254,8 +303,8 @@ warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\
     error (EXIT_FAILURE, 0, _("%s and %s are mutually exclusive"),
           "--sort-output", "--sort-by-file");
 
-  /* merge the two files */
-  result = merge (argv[optind], argv[optind + 1]);
+  /* Merge the two files.  */
+  result = merge (argv[optind], argv[optind + 1], &def);
 
   /* Sort the results.  */
   if (sort_by_filepos)
@@ -263,8 +312,43 @@ warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\
   else if (sort_by_msgid)
     msgdomain_list_sort_by_msgid (result);
 
-  /* Write the merged message list out.  */
-  msgdomain_list_print (result, output_file, force_po, false);
+  if (update_mode)
+    {
+      /* Do nothing if the original file and the result are equal.  */
+      if (!msgdomain_list_equal (def, result))
+       {
+         /* Back up def.po.  */
+         enum backup_type backup_type;
+         char *backup_file;
+
+         output_file = argv[optind];
+
+         if (backup_suffix_string == NULL)
+           {
+             backup_suffix_string = getenv ("SIMPLE_BACKUP_SUFFIX");
+             if (backup_suffix_string != NULL
+                 && backup_suffix_string[0] == '\0')
+               backup_suffix_string = NULL;
+           }
+         if (backup_suffix_string != NULL)
+           simple_backup_suffix = backup_suffix_string;
+
+         backup_type = xget_version (_("backup type"), version_control_string);
+         if (backup_type != none)
+           {
+             backup_file = find_backup_file_name (output_file, backup_type);
+             copy_file (output_file, backup_file);
+           }
+
+         /* Write the merged message list out.  */
+         msgdomain_list_print (result, output_file, true, false);
+       }
+    }
+  else
+    {
+      /* Write the merged message list out.  */
+      msgdomain_list_print (result, output_file, force_po, false);
+    }
 
   exit (EXIT_SUCCESS);
 }
@@ -315,10 +399,33 @@ Input file location:\n\
       printf ("\n");
       /* xgettext: no-wrap */
       printf (_("\
+Operation mode:\n\
+  -U, --update                update def.po,\n\
+                              do nothing if def.po already up to date\n\
+"));
+      printf ("\n");
+      /* xgettext: no-wrap */
+      printf (_("\
 Output file location:\n\
   -o, --output-file=FILE      write output to specified file\n\
 The results are written to standard output if no output file is specified\n\
 or if it is -.\n\
+"));
+      printf ("\n");
+      /* xgettext: no-wrap */
+      printf (_("\
+Output file location in update mode:\n\
+The result is written back to def.po.\n\
+      --backup=CONTROL        make a backup of def.po\n\
+      --suffix=SUFFIX         override the usual backup suffix\n\
+The version control method may be selected via the --backup option or through\n\
+the VERSION_CONTROL environment variable.  Here are the values:\n\
+  none, off       never make backups (even if --backup is given)\n\
+  numbered, t     make numbered backups\n\
+  existing, nil   numbered if numbered backups exist, simple otherwise\n\
+  simple, never   always make simple backups\n\
+The backup suffix is `~', unless set with --suffix or the SIMPLE_BACKUP_SUFFIX\n\
+environment variable.\n\
 "));
       printf ("\n");
       /* xgettext: no-wrap */
@@ -374,7 +481,7 @@ compendium (filename)
 }
 
 
-#define DOT_FREQUENCE 10
+#define DOT_FREQUENCY 10
 
 static void
 match_domain (fn1, fn2, definitions, refmlp, resultmlp, stats, processed)
@@ -395,7 +502,7 @@ match_domain (fn1, fn2, definitions, refmlp, resultmlp, stats, processed)
 
       /* Because merging can take a while we print something to signal
         we are not dead.  */
-      if (!quiet && verbosity_level <= 1 && *processed % DOT_FREQUENCE == 0)
+      if (!quiet && verbosity_level <= 1 && *processed % DOT_FREQUENCY == 0)
        fputc ('.', stderr);
 
       refmsg = refmlp->item[j];
@@ -471,9 +578,10 @@ this message is used but not defined in %s"), fn1);
 }
 
 static msgdomain_list_ty *
-merge (fn1, fn2)
+merge (fn1, fn2, defp)
      const char *fn1;                  /* definitions */
      const char *fn2;                  /* references */
+     msgdomain_list_ty **defp;         /* return definition list */
 {
   msgdomain_list_ty *def;
   msgdomain_list_ty *ref;
@@ -570,10 +678,13 @@ merge (fn1, fn2)
            {
              /* Remember the old translation although it is not used anymore.
                 But we mark it as obsolete.  */
-             defmsg->obsolete = true;
+             message_ty *mp;
+
+             mp = message_copy (defmsg);
+             mp->obsolete = true;
 
              message_list_append (msgdomain_list_sublist (result, domain, 1),
-                                  defmsg);
+                                  mp);
              stats.obsolete++;
            }
        }
@@ -591,5 +702,7 @@ merged %ld, fuzzied %ld, missing %ld, obsolete %ld.\n"),
   else if (!quiet)
     fputs (_(" done.\n"), stderr);
 
+  /* Return results.  */
+  *defp = def;
   return result;
 }