]> git.ipfire.org Git - thirdparty/gettext.git/commitdiff
Unify three PO file parsers into a single one, as far as possible.
authorBruno Haible <bruno@clisp.org>
Thu, 24 Apr 2003 10:55:35 +0000 (10:55 +0000)
committerBruno Haible <bruno@clisp.org>
Tue, 23 Jun 2009 10:10:24 +0000 (12:10 +0200)
17 files changed:
gettext-tools/src/ChangeLog
gettext-tools/src/FILES
gettext-tools/src/Makefile.am
gettext-tools/src/Makefile.msvc
gettext-tools/src/Makefile.vms
gettext-tools/src/msgcmp.c
gettext-tools/src/msgfmt.c
gettext-tools/src/msgmerge.c
gettext-tools/src/po-gram-gen.y
gettext-tools/src/po-hash-gen.y
gettext-tools/src/po-hash.h
gettext-tools/src/read-po-abstract.c [moved from gettext-tools/src/po.c with 60% similarity]
gettext-tools/src/read-po-abstract.h [moved from gettext-tools/src/po.h with 58% similarity]
gettext-tools/src/read-po.c
gettext-tools/src/read-po.h
gettext-tools/src/x-po.c
gettext-tools/src/xgettext.c

index 802ed8334f4c842e125e471f606bc5ba98b071ac..ec96ab1d48b18595bf88db03d0c6d74015b69153 100644 (file)
@@ -1,3 +1,96 @@
+2003-04-13  Bruno Haible  <bruno@clisp.org>
+
+       Unify three PO file parsers.
+       * read-po-abstract.h: Renamed from po.h.
+       (abstract_po_reader_class_ty): Renamed from po_method_ty.
+       (abstract_po_reader_ty): Renamed from po_ty.
+       (ABSTRACT_PO_READER_TY): Renamed from PO_BASE_TY.
+       (po_reader_alloc): Renamed from po_alloc.
+       (po_reader_free): Renamed from po_free.
+       * read-po-abstract.c: Renamed from po.c.
+       (po_reader_alloc): Renamed from po_alloc.
+       (po_reader_free): Renamed from po_free.
+       (call_parse_brief): Renamed from po_parse_brief.
+       (call_parse_debrief): Renamed from po_parse_debrief.
+       (call_directive_domain): Renamed from po_directive_domain.
+       (call_directive_message): Renamed from po_directive_message.
+       (call_comment): Renamed from po_comment.
+       (call_comment_dot): Renamed from po_comment_dot.
+       (call_comment_filepos): Renamed from po_comment_filepos.
+       (call_comment_special): Renamed from po_comment_special.
+       * read-po.h: Include read-po-abstract.h.
+       (default_po_reader_class_ty, default_po_reader_ty): New types.
+       (ABSTRACT_PO_READER_TY): New macro.
+       (default_constructor, default_destructor, default_parse_brief,
+       default_parse_debrief, default_directive_domain,
+       default_directive_message, default_comment, default_comment_dot,
+       default_comment_filepos, default_comment_special, default_set_domain,
+       default_add_message): New declarations.
+       (default_po_reader_alloc): New declaration.
+       * read-po.c (default_po_reader_ty): Renamed from readall_class_ty.
+       Add fields handle_comments, handle_filepos_comments,
+       allow_domain_directives, allow_duplicates,
+       allow_duplicates_if_same_msgstr.
+       (call_set_domain, call_add_message, call_frob_new_message): New
+       functions.
+       (default_constructor): Renamed from readall_constructor. Don't set
+       this->mdlp and this->mlp.
+       (default_destructor): Renamed from readall_destructor.
+       (default_parse_brief): Renamed from readall_parse_brief.
+       (default_parse_debrief): New function.
+       (default_copy_comment_state, default_reset_comment_state): New
+       functions.
+       (default_directive_domain): Renamed from readall_directive_domain.
+       Call set_domain method.
+       (default_directive_message): Renamed from readall_directive_message.
+       Call add_message method.
+       (default_comment): Renamed from readall_comment.
+       (default_comment_dot): Renamed from readall_comment_dot.
+       (default_comment_filepos): Renamed from readall_comment_filepos.
+       (default_comment_special): Renamed from readall_comment_special.
+       (default_set_domain, default_add_message): New functions.
+       (default_methods): Renamed from readall_methods.
+       (default_po_reader_alloc): New function.
+       (read_po, read_po_file): Update.
+       * msgfmt.c: Include read-po.h instead of po.h.
+       (msgfmt_po_reader_ty): Renamed from msgfmt_class_ty. Inherit
+       from default_po_reader_ty.
+       (main): Drop po_lex_pass_comments call, done by default_parse_brief.
+       (msgfmt_constructor): Renamed from format_constructor. Call superclass
+       function.
+       (msgfmt_parse_debrief): Renamed from format_debrief. Call superclass
+       function.
+       (format_directive_domain): Remove function.
+       (msgfmt_set_domain): New function.
+       (format_directive_message): Remove function.
+       (msgfmt_add_message, msgfmt_frob_new_message): New functions.
+       (msgfmt_comment_special): Renamed from format_comment_special.
+       (msgfmt_methods): Renamed from format_methods.
+       (read_po_file_msgfmt): Renamed from read_po_file.
+       * x-po.c: Include read-po.h instead of po.h.
+       (extract_class_ty, extract_constructor, extract_directive_domain,
+       extract_directive_message, extract_parse_brief, extract_comment,
+       extract_comment_dot, extract_comment_filepos, extract_comment_special):
+       Remove functions.
+       (extract_add_message): New function.
+       (extract_methods): Update.
+       (extract_po): Update.
+       * xgettext.c: Include read-po-abstract.h instead of po.h.
+       (exclude_directive_domain, exclude_directive_message, exclude_methods,
+       read_exclusion_file): Update.
+       * msgcmp.c: Don't include po.h.
+       * msgmerge.c: Likewise.
+       * po-gram-gen.y: Include read-po-abstract.h instead of po.h.
+       * po-hash-gen.y: Likewise.
+       (po_parse_comment_filepos): Renamed from po_hash.
+       * po-hash.h (po_parse_comment_filepos): Renamed from po_hash.
+       * Makefile.am (noinst_HEADERS): Remove po.h, add read-po-abstract.h.
+       (COMMON_SOURCE): Remove po.c, add read-po-abstract.c.
+       * Makefile.msvc (OBJECTS): Remove po.obj, add read-po-abstract.obj.
+       (read-po-abstract.obj): Renamed from po.obj.
+       * Makefile.vms (OBJECTS): Remove po.obj, add read-po-abstract.obj.
+       (read-po-abstract.obj): Renamed from po.obj.
+
 2003-04-13  Bruno Haible  <bruno@clisp.org>
 
        * write-po.h (message_print_comment, message_print_comment_dot,
index 1a932409828acfed11d2a9eedb28dc4abb62031c..d8b35fa2fa41383c1f3e9ecef48c51a45ffc5e52 100644 (file)
@@ -1,11 +1,7 @@
                 Short description of the source files
                 =====================================
 
-1)
-gettext.c       Source for the 'gettext' program.
-ngettext.c      Source for the 'ngettext' program.
-
-2) The msg* and xgettext programs.
+The msg* and xgettext programs.
 
 Bottom-up structure:
 
@@ -53,14 +49,14 @@ write-po.c
 | po-lex.c
 |               Lexical analysis of PO files.
 |
-| po.h
+| read-po-abstract.h
 | po-hash.h
 | po-hash-gen.y
 | po-gram.h
 | po-gram-gen.y
-| po.c
+| read-po-abstract.c
 |               Parsing of PO files.
-|         po.h
+|         read-po-abstract.h
 |                       General parser structure.
 |         po-hash.h
 |         po-hash-gen.y
@@ -69,7 +65,7 @@ write-po.c
 |         po-gram.h
 |         po-gram-gen.y
 |                       Parsing of PO files, based on po-lex.{h,c}.
-|         po.c
+|         read-po-abstract.c
 |                       Top-level parser functions and callbacks.
 |
 | read-po.h
index 0adb58985fd143ee856cbc49074d037829038386..15103e8227ad827b2f9797ab43284e2cb5901712 100644 (file)
@@ -35,13 +35,13 @@ lib_LTLIBRARIES = libgettextsrc.la libgettextpo.la
 include_HEADERS = gettext-po.h
 
 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-gram-gen2.h po-hash-gen.h msgl-charset.h msgl-equal.h \
-msgl-iconv.h msgl-ascii.h msgl-cat.h msgl-english.h msgfmt.h msgunfmt.h \
-read-mo.h write-mo.h read-java.h write-java.h read-tcl.h write-tcl.h \
-po-time.h plural-table.h format.h xgettext.h x-c.h x-po.h x-python.h x-lisp.h \
-x-elisp.h x-librep.h x-smalltalk.h x-java.h x-awk.h x-ycp.h x-tcl.h x-php.h \
-x-rst.h x-glade.h
+open-po.h read-po-abstract.h read-po.h str-list.h write-po.h dir-list.h \
+file-list.h po-gram-gen.h po-gram-gen2.h po-hash-gen.h msgl-charset.h \
+msgl-equal.h msgl-iconv.h msgl-ascii.h msgl-cat.h msgl-english.h msgfmt.h \
+msgunfmt.h read-mo.h write-mo.h read-java.h write-java.h read-tcl.h \
+write-tcl.h po-time.h plural-table.h format.h xgettext.h x-c.h x-po.h \
+x-python.h x-lisp.h x-elisp.h x-librep.h x-smalltalk.h x-java.h x-awk.h \
+x-ycp.h x-tcl.h x-php.h x-rst.h x-glade.h
 
 EXTRA_DIST += FILES project-id ChangeLog.0
 
@@ -80,12 +80,12 @@ JAVACOMP = $(SHELL) ../lib/javacomp.sh
 # All programs deal with message lists.
 # All programs must read PO files. (msgunfmt also, for read-java.c.)
 # message.c -> str-list.c.
-# (po.c <--> po-hash-gen.y <--> po-gram-gen.y <--> po-lex.c) -> str-list.c.
-# (po.c <--> po-hash-gen.y <--> po-gram-gen.y <--> po-lex.c) -> open-po.c -> dir-list.c -> str-list.c.
-# (po.c <--> po-hash-gen.y <--> po-gram-gen.y <--> po-lex.c) -> po-charset.c.
-# (po.c <--> po-hash-gen.y <--> po-gram-gen.y <--> po-lex.c) -> message.c -> str-list.c.
+# (read-po-abstract.c <--> po-hash-gen.y <--> po-gram-gen.y <--> po-lex.c) -> str-list.c.
+# (read-po-abstract.c <--> po-hash-gen.y <--> po-gram-gen.y <--> po-lex.c) -> open-po.c -> dir-list.c -> str-list.c.
+# (read-po-abstract.c <--> po-hash-gen.y <--> po-gram-gen.y <--> po-lex.c) -> po-charset.c.
+# (read-po-abstract.c <--> po-hash-gen.y <--> po-gram-gen.y <--> po-lex.c) -> message.c -> str-list.c.
 COMMON_SOURCE = message.c \
-po.c po-lex.c po-gram-gen.y po-hash-gen.y po-charset.c \
+read-po-abstract.c po-lex.c po-gram-gen.y po-hash-gen.y po-charset.c \
 open-po.c dir-list.c str-list.c
 
 # xgettext and msgfmt deal with format strings.
index d776e00b8a7df4b755a1ef2d453c41b9ed8888b4..a824f10f518d49d7cf245c3f92bd410945d19c26 100644 (file)
@@ -104,7 +104,7 @@ msgattrib.exe msgcat.exe msgcomm.exe msgconv.exe msgen.exe msgexec.exe msgfilter
 
 OBJECTS = \
   message.obj \
-  po.obj \
+  read-po-abstract.obj \
   po-lex.obj \
   po-gram-gen.obj \
   po-hash-gen.obj \
@@ -163,8 +163,8 @@ all : gettextsrc.lib $(PROGRAMS)
 message.obj : message.c
        $(CC) $(INCLUDES) $(CFLAGS) $(PICFLAGS) -c message.c
 
-po.obj : po.c
-       $(CC) $(INCLUDES) $(CFLAGS) $(PICFLAGS) -c po.c
+read-po-abstract.obj : read-po-abstract.c
+       $(CC) $(INCLUDES) $(CFLAGS) $(PICFLAGS) -c read-po-abstract.c
 
 po-lex.obj : po-lex.c
        $(CC) $(INCLUDES) $(CFLAGS) $(PICFLAGS) -c po-lex.c
index 979beb566df66ee4645d133221e39b8c080b4f31..481c3d3848233789bcfde01a053d4a88179ad002 100644 (file)
@@ -52,7 +52,7 @@ PROGRAMS = msgcmp.exe, msgfmt.exe, msgmerge.exe, msgunfmt.exe, xgettext.exe, msg
 
 OBJECTS = \
   message.obj, \
-  po.obj, \
+  read-po-abstract.obj, \
   po-lex.obj, \
   po-gram-gen.obj, \
   po-hash-gen.obj, \
@@ -109,8 +109,8 @@ all : gettextsrc.olb,$(PROGRAMS)
 message.obj : message.c
        $(CC) $(INCLUDES) $(CFLAGS) /define=($(DEFS)) message.c
 
-po.obj : po.c
-       $(CC) $(INCLUDES) $(CFLAGS) /define=($(DEFS)) po.c
+read-po-abstract.obj : read-po-abstract.c
+       $(CC) $(INCLUDES) $(CFLAGS) /define=($(DEFS)) read-po-abstract.c
 
 po-lex.obj : po-lex.c
        $(CC) $(INCLUDES) $(CFLAGS) /define=($(DEFS)) po-lex.c
index 9d60745b6810ba2be5d21fc7e2dc6c56da759535..d1f56e21f3e54a4bdebf36cb9f43fb7bd09a9ed1 100644 (file)
@@ -35,7 +35,6 @@
 #include "message.h"
 #include "exit.h"
 #include "read-po.h"
-#include "po.h"
 #include "msgl-iconv.h"
 #include "strstr.h"
 #include "strcase.h"
index 322f078967b6bc418de969a5ca5dbe55fe189877..f84458f39ccccb281f6a1e3de5417279de9f668e 100644 (file)
@@ -50,7 +50,7 @@
 
 #include "gettext.h"
 #include "message.h"
-#include "po.h"
+#include "read-po.h"
 
 #define _(str) gettext (str)
 
 # define USE_SIGINFO 1
 #endif
 
-/* This structure defines a derived class of the po_ty class.  (See
-   po.h for an explanation.)  */
-typedef struct msgfmt_class_ty msgfmt_class_ty;
-struct msgfmt_class_ty
-{
-  /* inherited instance variables, etc */
-  PO_BASE_TY
-
-  bool is_fuzzy;
-  enum is_format is_format[NFORMATS];
-  enum is_wrap do_wrap;
-
-  bool has_header_entry;
-  bool has_nonfuzzy_header_entry;
-};
-
 /* Contains exit status for case in which no premature exit occurs.  */
 static int exit_status;
 
@@ -196,7 +180,7 @@ static const char *add_mo_suffix (const char *);
 static struct msg_domain *new_domain (const char *name, const char *file_name);
 static bool is_nonobsolete (const message_ty *mp);
 static void check_plural (message_list_ty *mlp);
-static void read_po_file (char *filename);
+static void read_po_file_msgfmt (char *filename);
 
 
 int
@@ -418,10 +402,6 @@ warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\
                  strict_uniforum ? add_mo_suffix (output_file_name)
                                  : output_file_name);
 
-  /* Prepare PO file reader.  We need to see the comments because inexact
-     translations must be reported.  */
-  po_lex_pass_comments (true);
-
   /* Process all given .po files.  */
   while (argc > optind)
     {
@@ -431,7 +411,7 @@ warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\
        current_domain = NULL;
 
       /* And process the input file.  */
-      read_po_file (argv[optind]);
+      read_po_file_msgfmt (argv[optind]);
 
       ++optind;
     }
@@ -1284,23 +1264,38 @@ field `%s' still has initial default value\n"),
 }
 
 
-/* The rest of the file is similar to read-po.c.  The differences are:
-   - Comments are not stored, they are discarded right away.
+/* The rest of the file defines a subclass msgfmt_po_reader_ty of
+   default_po_reader_ty.  Its particularities are:
    - The header entry check is performed on-the-fly.
+   - Comments are not stored, they are discarded right away.
+     (This is achieved by setting handle_comments = false and
+     handle_filepos_comments = false.)
+   - The multi-domain handling is adapted to our domain_list.
  */
 
 
+/* This structure defines a derived class of the default_po_reader_ty class.
+   (See read-po-abstract.h for an explanation.)  */
+typedef struct msgfmt_po_reader_ty msgfmt_po_reader_ty;
+struct msgfmt_po_reader_ty
+{
+  /* inherited instance variables, etc */
+  DEFAULT_PO_READER_TY
+
+  bool has_header_entry;
+  bool has_nonfuzzy_header_entry;
+};
+
+
 /* Prepare for first message.  */
 static void
-format_constructor (po_ty *that)
+msgfmt_constructor (abstract_po_reader_ty *that)
 {
-  msgfmt_class_ty *this = (msgfmt_class_ty *) that;
-  size_t i;
+  msgfmt_po_reader_ty *this = (msgfmt_po_reader_ty *) that;
+
+  /* Invoke superclass constructor.  */
+  default_constructor (that);
 
-  this->is_fuzzy = false;
-  for (i = 0; i < NFORMATS; i++)
-    this->is_format[i] = undecided;
-  this->do_wrap = undecided;
   this->has_header_entry = false;
   this->has_nonfuzzy_header_entry = false;
 }
@@ -1308,9 +1303,12 @@ format_constructor (po_ty *that)
 
 /* Some checks after whole file is read.  */
 static void
-format_debrief (po_ty *that)
+msgfmt_parse_debrief (abstract_po_reader_ty *that)
 {
-  msgfmt_class_ty *this = (msgfmt_class_ty *) that;
+  msgfmt_po_reader_ty *this = (msgfmt_po_reader_ty *) that;
+
+  /* Invoke superclass method.  */
+  default_parse_debrief (that);
 
   /* Test whether header entry was found.  */
   if (check_header)
@@ -1340,9 +1338,9 @@ warning: older versions of msgfmt will give an error on this\n")));
 }
 
 
-/* Process `domain' directive from .po file.  */
+/* Set 'domain' directive when seen in .po file.  */
 static void
-format_directive_domain (po_ty *pop, char *name)
+msgfmt_set_domain (default_po_reader_ty *this, char *name)
 {
   /* If no output file was given, we change it with each `domain'
      directive.  */
@@ -1368,143 +1366,120 @@ domain name \"%s\" not suitable as file name: will use prefix"), name);
 
       /* Set new domain.  */
       current_domain = new_domain (name, add_mo_suffix (name));
+      this->domain = current_domain->domain_name;
+      this->mlp = current_domain->mlp;
     }
   else
     {
       if (check_domain)
-       error (0, 0, _("`domain %s' directive ignored"), name);
+       po_gram_error_at_line (&gram_pos,
+                              _("`domain %s' directive ignored"), name);
 
-      /* NAME was allocated in po-gram.y but is not used anywhere.  */
+      /* NAME was allocated in po-gram-gen.y but is not used anywhere.  */
       free (name);
     }
 }
 
 
-/* Process `msgid'/`msgstr' pair from .po file.  */
-static void
-format_directive_message (po_ty *that,
-                         char *msgid_string,
-                         lex_pos_ty *msgid_pos,
-                         char *msgid_plural,
-                         char *msgstr_string, size_t msgstr_len,
-                         lex_pos_ty *msgstr_pos,
-                         bool obsolete)
+void
+msgfmt_add_message (default_po_reader_ty *this,
+                   char *msgid,
+                   lex_pos_ty *msgid_pos,
+                   char *msgid_plural,
+                   char *msgstr, size_t msgstr_len,
+                   lex_pos_ty *msgstr_pos,
+                   bool obsolete)
 {
-  msgfmt_class_ty *this = (msgfmt_class_ty *) that;
-  message_ty *mp;
-  size_t i;
-
   /* Check whether already a domain is specified.  If not, use default
      domain.  */
   if (current_domain == NULL)
-    current_domain = new_domain (MESSAGE_DOMAIN_DEFAULT,
-                                add_mo_suffix (MESSAGE_DOMAIN_DEFAULT));
-
-  /* Duplicate checking.  */
-  mp = message_list_search (current_domain->mlp, msgid_string);
-  if (mp)
     {
-      /* We give a fatal error about this, regardless whether the
-        translations are equal or different.  This is for consistency
-        with msgmerge, msgcat and others.  The user can use the
-        msguniq program to get rid of duplicates.  */
-      po_gram_error_at_line (msgid_pos, _("duplicate message definition"));
-      po_gram_error_at_line (&mp->pos, _("\
-...this is the location of the first definition"));
-
-      /* We don't need the just constructed entries' parameter string
-        (allocated in po-gram.y).  */
-      free (msgid_string);
-      free (msgstr_string);
+      current_domain = new_domain (MESSAGE_DOMAIN_DEFAULT,
+                                  add_mo_suffix (MESSAGE_DOMAIN_DEFAULT));
+      /* Keep current_domain and this->domain synchronized.  */
+      this->domain = current_domain->domain_name;
+      this->mlp = current_domain->mlp;
     }
-  else
+
+  /* Invoke superclass method.  */
+  default_add_message (this, msgid, msgid_pos, msgid_plural,
+                      msgstr, msgstr_len, msgstr_pos, obsolete);
+}
+
+
+static void
+msgfmt_frob_new_message (default_po_reader_ty *that, message_ty *mp,
+                        const lex_pos_ty *msgid_pos,
+                        const lex_pos_ty *msgstr_pos)
+{
+  msgfmt_po_reader_ty *this = (msgfmt_po_reader_ty *) that;
+
+  if (!mp->obsolete)
     {
-      /* Construct message to add to the list.
-        Non-obsolete messages will be output.
-        Obsolete message go into the list only for duplicate checking.  */
-      mp = message_alloc (NULL, NULL, msgstr_string, msgstr_len, msgstr_pos);
-      mp->msgid = msgid_string;
-      mp->msgid_plural = msgid_plural;
-      mp->obsolete = obsolete;
-      for (i = 0; i < NFORMATS; i++)
-       mp->is_format[i] = this->is_format[i];
-
-      if (!obsolete)
+      /* Don't emit untranslated entries.
+        Also don't emit fuzzy entries, unless --use-fuzzy was specified.
+        But ignore fuzziness of the header entry.  */
+      if (mp->msgstr[0] == '\0'
+         || (!include_all && mp->is_fuzzy && mp->msgid[0] != '\0'))
        {
-         /* Don't emit untranslated entries.
-            Also don't emit fuzzy entries, unless --use-fuzzy was specified.
-            But ignore fuzziness of the header entry.  */
-         if (msgstr_string[0] == '\0'
-             || (!include_all && this->is_fuzzy && msgid_string[0] != '\0'))
+         if (check_compatibility)
            {
-             if (check_compatibility)
-               {
-                 error_with_progname = false;
-                 error_at_line (0, 0, msgstr_pos->file_name,
-                                msgstr_pos->line_number,
-                                (msgstr_string[0] == '\0'
-                                 ? _("empty `msgstr' entry ignored")
-                                 : _("fuzzy `msgstr' entry ignored")));
-                 error_with_progname = true;
-               }
-
-             /* Increment counter for fuzzy/untranslated messages.  */
-             if (msgstr_string[0] == '\0')
-               ++msgs_untranslated;
-             else
-               ++msgs_fuzzy;
-
-             mp->obsolete = true;
+             error_with_progname = false;
+             error_at_line (0, 0, mp->pos.file_name, mp->pos.line_number,
+                            (mp->msgstr[0] == '\0'
+                             ? _("empty `msgstr' entry ignored")
+                             : _("fuzzy `msgstr' entry ignored")));
+             error_with_progname = true;
            }
+
+         /* Increment counter for fuzzy/untranslated messages.  */
+         if (mp->msgstr[0] == '\0')
+           ++msgs_untranslated;
          else
+           ++msgs_fuzzy;
+
+         mp->obsolete = true;
+       }
+      else
+       {
+         /* Test for header entry.  */
+         if (mp->msgid[0] == '\0')
            {
-             /* Test for header entry.  */
-             if (msgid_string[0] == '\0')
-               {
-                 this->has_header_entry = true;
-                 if (!this->is_fuzzy)
-                   this->has_nonfuzzy_header_entry = true;
-
-                 /* Do some more tests on the contents of the header
-                    entry.  */
-                 if (check_header)
-                   check_header_entry (msgstr_string);
-               }
-             else
-               /* We don't count the header entry in the statistic so place
-                  the counter incrementation here.  */
-               if (this->is_fuzzy)
-                 ++msgs_fuzzy;
-               else
-                 ++msgs_translated;
-
-             /* Do some more checks on both strings.  */
-             check_pair (msgid_string, msgid_pos, msgid_plural,
-                         msgstr_string, msgstr_len, msgstr_pos,
-                         this->is_format);
+             this->has_header_entry = true;
+             if (!mp->is_fuzzy)
+               this->has_nonfuzzy_header_entry = true;
+
+             /* Do some more tests on the contents of the header entry.  */
+             if (check_header)
+               check_header_entry (mp->msgstr);
            }
+         else
+           /* We don't count the header entry in the statistic so place
+              the counter incrementation here.  */
+           if (mp->is_fuzzy)
+             ++msgs_fuzzy;
+           else
+             ++msgs_translated;
+
+         /* Do some more checks on both strings.  */
+         check_pair (mp->msgid, msgid_pos, mp->msgid_plural,
+                     mp->msgstr, mp->msgstr_len, msgstr_pos,
+                     mp->is_format);
        }
-      message_list_append (current_domain->mlp, mp);
     }
-
-  /* Prepare for next message.  */
-  this->is_fuzzy = false;
-  for (i = 0; i < NFORMATS; i++)
-    this->is_format[i] = undecided;
-  this->do_wrap = undecided;
 }
 
 
 /* Test for `#, fuzzy' comments and warn.  */
 static void
-format_comment_special (po_ty *that, const char *s)
+msgfmt_comment_special (abstract_po_reader_ty *that, const char *s)
 {
-  msgfmt_class_ty *this = (msgfmt_class_ty *) that;
-  bool fuzzy;
+  msgfmt_po_reader_ty *this = (msgfmt_po_reader_ty *) that;
 
-  po_parse_comment_special (s, &fuzzy, this->is_format, &this->do_wrap);
+  /* Invoke superclass method.  */
+  default_comment_special (that, s);
 
-  if (fuzzy)
+  if (this->is_fuzzy)
     {
       static bool warned = false;
 
@@ -1515,8 +1490,6 @@ format_comment_special (po_ty *that, const char *s)
 %s: warning: source file contains fuzzy translation"),
                 gram_pos.file_name);
        }
-
-      this->is_fuzzy = true;
     }
 }
 
@@ -1527,30 +1500,48 @@ format_comment_special (po_ty *that, const char *s)
    and all actions resulting from the parse will be through
    invocations of method functions of that object.  */
 
-static po_method_ty format_methods =
+static default_po_reader_class_ty msgfmt_methods =
 {
-  sizeof (msgfmt_class_ty),
-  format_constructor, /* constructor */
-  NULL, /* destructor */
-  format_directive_domain,
-  format_directive_message,
-  NULL, /* parse_brief */
-  format_debrief, /* parse_debrief */
-  NULL, /* comment */
-  NULL, /* comment_dot */
-  NULL, /* comment_filepos */
-  format_comment_special /* comment */
+  {
+    sizeof (msgfmt_po_reader_ty),
+    msgfmt_constructor,
+    default_destructor,
+    default_parse_brief,
+    msgfmt_parse_debrief,
+    default_directive_domain,
+    default_directive_message,
+    default_comment,
+    default_comment_dot,
+    default_comment_filepos,
+    msgfmt_comment_special
+  },
+  msgfmt_set_domain, /* set_domain */
+  msgfmt_add_message, /* add_message */
+  msgfmt_frob_new_message /* frob_new_message */
 };
 
 
 /* Read .po file FILENAME and store translation pairs.  */
 static void
-read_po_file (char *filename)
+read_po_file_msgfmt (char *filename)
 {
-  po_ty *pop;
-
-  pop = po_alloc (&format_methods);
+  default_po_reader_ty *pop;
+
+  pop = default_po_reader_alloc (&msgfmt_methods);
+  pop->handle_comments = false;
+  pop->handle_filepos_comments = false;
+  pop->allow_domain_directives = true;
+  pop->allow_duplicates = false;
+  pop->allow_duplicates_if_same_msgstr = false;
+  pop->mdlp = NULL;
+  pop->mlp = NULL;
+  if (current_domain != NULL)
+    {
+      /* Keep current_domain and this->domain synchronized.  */
+      pop->domain = current_domain->domain_name;
+      pop->mlp = current_domain->mlp;
+    }
   po_lex_pass_obsolete_entries (true);
-  po_scan_file (pop, filename);
-  po_free (pop);
+  po_scan_file ((abstract_po_reader_ty *) pop, filename);
+  po_reader_free ((abstract_po_reader_ty *) pop);
 }
index 347704423ec4251f35b9c1b53e6bdfbb290e15b1..6198df4028ec74edaa2a4c58ba99a768ac473ee5 100644 (file)
@@ -44,7 +44,6 @@
 #include "strcase.h"
 #include "stpcpy.h"
 #include "stpncpy.h"
-#include "po.h"
 #include "msgl-iconv.h"
 #include "msgl-equal.h"
 #include "plural-exp.h"
index 2850ef90e66c7b1b99415560803938bcdbe4b6ca..355ffba67b4aa5ff80e1437c40d1a9c40172d9c0 100644 (file)
@@ -1,5 +1,5 @@
 /* GNU gettext - internationalization aids
-   Copyright (C) 1995, 1996, 1998, 2000, 2001 Free Software Foundation, Inc.
+   Copyright (C) 1995-1996, 1998, 2000-2001, 2003 Free Software Foundation, Inc.
 
    This file was written by Peter Miller <pmiller@agso.gov.au>
 
@@ -34,7 +34,7 @@
 #include "error.h"
 #include "xmalloc.h"
 #include "gettext.h"
-#include "po.h"
+#include "read-po-abstract.h"
 
 #define _(str) gettext (str)
 
index 4bdcbc00c2c61b9130b49aaaf2f5c22321c9fc13..71f40ac04e5e98925cfed26a9f36f0ce33100949 100644 (file)
@@ -1,5 +1,5 @@
 /* GNU gettext - internationalization aids
-   Copyright (C) 1995-1996, 1998, 2001-2002 Free Software Foundation, Inc.
+   Copyright (C) 1995-1996, 1998, 2001-2003 Free Software Foundation, Inc.
 
    This file was written by Peter Miller <pmiller@agso.gov.au>
 
@@ -40,7 +40,7 @@
 #include <string.h>
 
 #include "xmalloc.h"
-#include "po.h"
+#include "read-po-abstract.h"
 
 /* Remap normal yacc parser interface names (yyparse, yylex, yyerror, etc),
    as well as gratuitiously global symbol names, so we can have multiple
@@ -303,7 +303,7 @@ yylex ()
 /* Analyze whether the string (a pseudo-comment line) contains file names
    and line numbers.  */
 int
-po_hash (const char *s)
+po_parse_comment_filepos (const char *s)
 {
   cur = s;
   last_was_colon = false;
index 7ffc716a98c5b7ea5246c5c5a9d2822470aa1edb..00218af098e965b5979a0a74b035aa9a4ad76414 100644 (file)
@@ -1,5 +1,5 @@
 /* GNU gettext - internationalization aids
-   Copyright (C) 1995-1996, 1998, 2001-2002 Free Software Foundation, Inc.
+   Copyright (C) 1995-1996, 1998, 2001-2003 Free Software Foundation, Inc.
 
    This file was written by Peter Miller <millerp@canb.auug.org.au>
 
@@ -24,6 +24,6 @@
    sign "#:" or "#".  If the string contains file names and line numbers,
    return 0 and call po_callback_comment_filepos for each of them.  Otherwise
    return nonzero.  */
-extern int po_hash (const char *string);
+extern int po_parse_comment_filepos (const char *string);
 
 #endif /* _PO_HASH_H */
similarity index 60%
rename from gettext-tools/src/po.c
rename to gettext-tools/src/read-po-abstract.c
index 1d2f4e3a9039d00fc7d589b7c48a026a77d2e348..666f98c6bc19b6ed65d52f40e56a0a697899452a 100644 (file)
@@ -1,4 +1,4 @@
-/* GNU gettext - internationalization aids
+/* Reading PO files, abstract class.
    Copyright (C) 1995-1996, 1998, 2000-2003 Free Software Foundation, Inc.
 
    This file was written by Peter Miller <millerp@canb.auug.org.au>
@@ -23,7 +23,7 @@
 #endif
 
 /* Specification.  */
-#include "po.h"
+#include "read-po-abstract.h"
 
 #include <stdlib.h>
 #include <string.h>
 #include "xmalloc.h"
 
 /* Local variables.  */
-static po_ty *callback_arg;
+static abstract_po_reader_ty *callback_arg;
 
 
-po_ty *
-po_alloc (po_method_ty *pomp)
+/* ========================================================================= */
+/* Allocating and freeing instances of abstract_po_reader_ty.  */
+
+
+abstract_po_reader_ty *
+po_reader_alloc (abstract_po_reader_class_ty *method_table)
 {
-  po_ty *pop;
+  abstract_po_reader_ty *pop;
 
-  pop = (po_ty *) xmalloc (pomp->size);
-  pop->method = pomp;
-  if (pomp->constructor)
-    pomp->constructor (pop);
+  pop = (abstract_po_reader_ty *) xmalloc (method_table->size);
+  pop->methods = method_table;
+  if (method_table->constructor)
+    method_table->constructor (pop);
   return pop;
 }
 
 
 void
-po_free (po_ty *pop)
+po_reader_free (abstract_po_reader_ty *pop)
 {
-  if (pop->method->destructor)
-    pop->method->destructor (pop);
+  if (pop->methods->destructor)
+    pop->methods->destructor (pop);
   free (pop);
 }
 
 
-static void
-po_parse_brief (po_ty *pop)
+/* ========================================================================= */
+/* Inline functions to invoke the methods.  */
+
+
+static inline void
+call_parse_brief (abstract_po_reader_ty *pop)
+{
+  if (pop->methods->parse_brief)
+    pop->methods->parse_brief (pop);
+}
+
+static inline void
+call_parse_debrief (abstract_po_reader_ty *pop)
+{
+  if (pop->methods->parse_debrief)
+    pop->methods->parse_debrief (pop);
+}
+
+static inline void
+call_directive_domain (abstract_po_reader_ty *pop, char *name)
 {
-  if (pop->method->parse_brief)
-    pop->method->parse_brief (pop);
+  if (pop->methods->directive_domain)
+    pop->methods->directive_domain (pop, name);
 }
 
+static inline void
+call_directive_message (abstract_po_reader_ty *pop,
+                       char *msgid,
+                       lex_pos_ty *msgid_pos,
+                       char *msgid_plural,
+                       char *msgstr, size_t msgstr_len,
+                       lex_pos_ty *msgstr_pos,
+                       bool obsolete)
+{
+  if (pop->methods->directive_message)
+    pop->methods->directive_message (pop, msgid, msgid_pos, msgid_plural,
+                                    msgstr, msgstr_len, msgstr_pos, obsolete);
+}
 
-static void
-po_parse_debrief (po_ty *pop)
+static inline void
+call_comment (abstract_po_reader_ty *pop, const char *s)
 {
-  if (pop->method->parse_debrief)
-    pop->method->parse_debrief (pop);
+  if (pop->methods->comment != NULL)
+    pop->methods->comment (pop, s);
 }
 
+static inline void
+call_comment_dot (abstract_po_reader_ty *pop, const char *s)
+{
+  if (pop->methods->comment_dot != NULL)
+    pop->methods->comment_dot (pop, s);
+}
+
+static inline void
+call_comment_filepos (abstract_po_reader_ty *pop, const char *name, size_t line)
+{
+  if (pop->methods->comment_filepos)
+    pop->methods->comment_filepos (pop, name, line);
+}
+
+static inline void
+call_comment_special (abstract_po_reader_ty *pop, const char *s)
+{
+  if (pop->methods->comment_special != NULL)
+    pop->methods->comment_special (pop, s);
+}
+
+
+/* ========================================================================= */
+/* Exported functions.  */
+
 
 void
-po_scan_start (po_ty *pop)
+po_scan_start (abstract_po_reader_ty *pop)
 {
   /* The parse will call the po_callback_... functions (see below)
      when the various directive are recognised.  The callback_arg
@@ -84,19 +144,19 @@ po_scan_start (po_ty *pop)
      have the relevant method invoked.  */
   callback_arg = pop;
 
-  po_parse_brief (pop);
+  call_parse_brief (pop);
 }
 
 void
-po_scan_end (po_ty *pop)
+po_scan_end (abstract_po_reader_ty *pop)
 {
-  po_parse_debrief (pop);
+  call_parse_debrief (pop);
   callback_arg = NULL;
 }
 
 
 void
-po_scan (po_ty *pop, FILE *fp,
+po_scan (abstract_po_reader_ty *pop, FILE *fp,
         const char *real_filename, const char *logical_filename)
 {
   /* Parse the stream's content.  */
@@ -109,7 +169,7 @@ po_scan (po_ty *pop, FILE *fp,
 
 
 void
-po_scan_file (po_ty *pop, const char *filename)
+po_scan_file (abstract_po_reader_ty *pop, const char *filename)
 {
   /* Open the file and parse it.  */
   lex_open (filename);
@@ -120,12 +180,9 @@ po_scan_file (po_ty *pop, const char *filename)
 }
 
 
-static void
-po_directive_domain (po_ty *pop, char *name)
-{
-  if (pop->method->directive_domain)
-    pop->method->directive_domain (pop, name);
-}
+/* ========================================================================= */
+/* Callbacks used by po-gram.y or po-hash.y or po-lex.c, indirectly
+   from po_scan.  */
 
 
 /* This function is called by po_gram_lex() whenever a domain directive
@@ -134,22 +191,7 @@ void
 po_callback_domain (char *name)
 {
   /* assert(callback_arg); */
-  po_directive_domain (callback_arg, name);
-}
-
-
-static void
-po_directive_message (po_ty *pop,
-                     char *msgid,
-                     lex_pos_ty *msgid_pos,
-                     char *msgid_plural,
-                     char *msgstr, size_t msgstr_len,
-                     lex_pos_ty *msgstr_pos,
-                     bool obsolete)
-{
-  if (pop->method->directive_message)
-    pop->method->directive_message (pop, msgid, msgid_pos, msgid_plural,
-                                   msgstr, msgstr_len, msgstr_pos, obsolete);
+  call_directive_domain (callback_arg, name);
 }
 
 
@@ -166,49 +208,18 @@ po_callback_message (char *msgid, lex_pos_ty *msgid_pos, char *msgid_plural,
   if (msgid[0] == '\0' && !obsolete)
     po_lex_charset_set (msgstr, gram_pos.file_name);
 
-  po_directive_message (callback_arg, msgid, msgid_pos, msgid_plural,
-                       msgstr, msgstr_len, msgstr_pos, obsolete);
-}
-
-
-static void
-po_comment (po_ty *pop, const char *s)
-{
-  if (pop->method->comment != NULL)
-    pop->method->comment (pop, s);
-}
-
-
-static void
-po_comment_dot (po_ty *pop, const char *s)
-{
-  if (pop->method->comment_dot != NULL)
-    pop->method->comment_dot (pop, s);
+  call_directive_message (callback_arg, msgid, msgid_pos, msgid_plural,
+                         msgstr, msgstr_len, msgstr_pos, obsolete);
 }
 
 
-static void
-po_comment_filepos (po_ty *pop, const char *name, size_t line)
-{
-  if (pop->method->comment_filepos)
-    pop->method->comment_filepos (pop, name, line);
-}
-
-
-/* This function is called by po_hash(), once for each filename.  */
+/* This function is called by po_parse_comment_filepos(), once for each
+   filename.  */
 void
 po_callback_comment_filepos (const char *name, size_t line)
 {
   /* assert(callback_arg); */
-  po_comment_filepos (callback_arg, name, line);
-}
-
-
-static void
-po_comment_special (po_ty *pop, const char *s)
-{
-  if (pop->method->comment_special != NULL)
-    pop->method->comment_special (pop, s);
+  call_comment_filepos (callback_arg, name, line);
 }
 
 
@@ -311,29 +322,30 @@ po_parse_comment_special (const char *s,
 
 /* This function is called by po_gram_lex() whenever a comment is
    seen.  It analyzes the comment to see what sort it is, and then
-   dispatches it to the appropriate method: po_comment, po_comment_dot,
-   po_comment_filepos (via po_hash), or po_comment_special.  */
+   dispatches it to the appropriate method: call_comment, call_comment_dot,
+   call_comment_filepos (via po_parse_comment_filepos), or
+   call_comment_special.  */
 void
 po_callback_comment (const char *s)
 {
   /* assert(callback_arg); */
   if (*s == '.')
-    po_comment_dot (callback_arg, s + 1);
+    call_comment_dot (callback_arg, s + 1);
   else if (*s == ':')
     {
       /* Parse the file location string.  If the parse succeeds, the
         appropriate callback will be invoked.  If the parse fails,
-        the po_hash function will return non-zero - so pretend it was
-        a normal comment.  */
-      if (po_hash (s + 1) == 0)
+        the po_parse_comment_filepos function will return non-zero - so
+        pretend it was a normal comment.  */
+      if (po_parse_comment_filepos (s + 1) == 0)
        /* Do nothing, it is a GNU-style file pos line.  */ ;
       else
-       po_comment (callback_arg, s + 1);
+       call_comment (callback_arg, s + 1);
     }
   else if (*s == ',' || *s == '!')
     {
       /* Get all entries in the special comment line.  */
-      po_comment_special (callback_arg, s + 1);
+      call_comment_special (callback_arg, s + 1);
     }
   else
     {
@@ -344,9 +356,9 @@ po_callback_comment (const char *s)
         appropriate callback will be invoked.  */
       if (s[0] == ' ' && (s[1] == 'F' || s[1] == 'f') && s[2] == 'i'
          && s[3] == 'l' && s[4] == 'e' && s[5] == ':'
-         && po_hash (s) == 0)
+         && po_parse_comment_filepos (s) == 0)
        /* Do nothing, it is a Sun-style file pos line.  */ ;
       else
-       po_comment (callback_arg, s);
+       call_comment (callback_arg, s);
     }
 }
similarity index 58%
rename from gettext-tools/src/po.h
rename to gettext-tools/src/read-po-abstract.h
index cdab89344cc7a668c629a928e7d0a4c228111a72..c7bb0cb57e44580d97fba53ea1f43ca2e5cb39e2 100644 (file)
@@ -1,4 +1,4 @@
-/* GNU gettext - internationalization aids
+/* Reading PO files, abstract class.
    Copyright (C) 1995-1996, 1998, 2000-2003 Free Software Foundation, Inc.
 
    This file was written by Peter Miller <millerp@canb.auug.org.au>
@@ -17,8 +17,8 @@
    along with this program; if not, write to the Free Software Foundation,
    Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
 
-#ifndef _PO_H
-#define _PO_H
+#ifndef _READ_PO_ABSTRACT_H
+#define _READ_PO_ABSTRACT_H
 
 #include "po-lex.h"
 #include "message.h"
    used to indicate a type name.  */
 
 /* The following pair of structures cooperate to create an "Object" in
-   the OO sense, we are simply doing it manually, rather than with the
+   the OO sense.  We are simply doing it manually, rather than with the
    help of an OO compiler.  This implementation allows polymorphism
-   and inheritance - more than enough for the immediate needs.
-
-   This first structure contains pointers to functions.  Each function
-   is a method for the class (base or derived).
-
-   Use a NULL pointer where no action is required.  */
+   and inheritance - more than enough for the immediate needs.  */
 
 /* Forward declaration.  */
-struct po_ty;
+struct abstract_po_reader_ty;
+
 
+/* This first structure, playing the role of the "Class" in OO sense,
+   contains pointers to functions.  Each function is a method for the
+   class (base or derived).  Use a NULL pointer where no action is
+   required.  */
 
-typedef struct po_method_ty po_method_ty;
-struct po_method_ty
+typedef struct abstract_po_reader_class_ty abstract_po_reader_class_ty;
+struct abstract_po_reader_class_ty
 {
-  /* how many bytes to malloc for this class */
+  /* how many bytes to malloc for an instance of this class */
   size_t size;
 
   /* what to do immediately after the instance is malloc()ed */
-  void (*constructor) (struct po_ty *pop);
+  void (*constructor) (struct abstract_po_reader_ty *pop);
 
   /* what to do immediately before the instance is free()ed */
-  void (*destructor) (struct po_ty *pop);
+  void (*destructor) (struct abstract_po_reader_ty *pop);
+
+  /* This method is invoked before the parse, but after the file is
+     opened by the lexer.  */
+  void (*parse_brief) (struct abstract_po_reader_ty *pop);
+
+  /* This method is invoked after the parse, but before the file is
+     closed by the lexer.  The intention is to make consistency checks
+     against the file here, and emit the errors through the lex_error*
+     functions.  */
+  void (*parse_debrief) (struct abstract_po_reader_ty *pop);
 
   /* what to do with a domain directive */
-  void (*directive_domain) (struct po_ty *pop, char *name);
+  void (*directive_domain) (struct abstract_po_reader_ty *pop, char *name);
 
   /* what to do with a message directive */
-  void (*directive_message) (struct po_ty *pop,
+  void (*directive_message) (struct abstract_po_reader_ty *pop,
                             char *msgid, lex_pos_ty *msgid_pos,
                             char *msgid_plural,
                             char *msgstr, size_t msgstr_len,
                             lex_pos_ty *msgstr_pos,
                             bool obsolete);
 
-  /* This method is invoked before the parse, but after the file is
-     opened by the lexer.  */
-  void (*parse_brief) (struct po_ty *pop);
-
-  /* This method is invoked after the parse, but before the file is
-     closed by the lexer.  The intention is to make consistency checks
-     against the file here, and emit the errors through the lex_error*
-     functions.  */
-  void (*parse_debrief) (struct po_ty *pop);
-
   /* What to do with a plain-vanilla comment - the expectation is that
      they will be accumulated, and added to the next message
      definition seen.  Or completely ignored.  */
-  void (*comment) (struct po_ty *pop, const char *s);
+  void (*comment) (struct abstract_po_reader_ty *pop, const char *s);
 
   /* What to do with a comment that starts with a dot (i.e.  extracted
      by xgettext) - the expectation is that they will be accumulated,
      and added to the next message definition seen.  Or completely
      ignored.  */
-  void (*comment_dot) (struct po_ty *pop, const char *s);
+  void (*comment_dot) (struct abstract_po_reader_ty *pop, const char *s);
 
   /* What to do with a file position seen in a comment (i.e. a message
      location comment extracted by xgettext) - the expectation is that
      they will be accumulated, and added to the next message
      definition seen.  Or completely ignored.  */
-  void (*comment_filepos) (struct po_ty *pop, const char *s, size_t line);
+  void (*comment_filepos) (struct abstract_po_reader_ty *pop,
+                          const char *s, size_t line);
 
   /* What to do with a comment that starts with a ',' or '!' - this is a
      special comment.  One of the possible uses is to indicate a
      inexact translation.  */
-  void (*comment_special) (struct po_ty *pop, const char *s);
+  void (*comment_special) (struct abstract_po_reader_ty *pop, const char *s);
 };
 
 
 /* This next structure defines the base class passed to the methods.
    Derived methods will often need to cast their first argument before
-   using it (this corresponds to the implicit ``this'' argument of many
-   C++ implementations).
+   using it (this corresponds to the implicit ``this'' argument in C++).
 
-   When declaring derived classes, use the PO_BASE_TY define at the
-   start of the structure, to declare inherited instance variables,
+   When declaring derived classes, use the ABSTRACT_PO_READER_TY define
+   at the start of the structure, to declare inherited instance variables,
    etc.  */
 
-#define PO_BASE_TY \
-  po_method_ty *method;
+#define ABSTRACT_PO_READER_TY \
+  abstract_po_reader_class_ty *methods;
 
-typedef struct po_ty po_ty;
-struct po_ty
+typedef struct abstract_po_reader_ty abstract_po_reader_ty;
+struct abstract_po_reader_ty
 {
-  PO_BASE_TY
+  ABSTRACT_PO_READER_TY
 };
 
 
-/* Allocate a fresh po_ty (or derived class) instance and call its
-   constructor.  */
-extern po_ty *po_alloc (po_method_ty *jtable);
+/* Allocate a fresh abstract_po_reader_ty (or derived class) instance and
+   call its constructor.  */
+extern abstract_po_reader_ty *
+       po_reader_alloc (abstract_po_reader_class_ty *method_table);
 
-/* Prepare for use of po_method_ty methods.  */
-extern void po_scan_start (po_ty *pop);
+/* Prepare for use of abstract_po_reader_class_ty methods.  */
+extern void
+       po_scan_start (abstract_po_reader_ty *pop);
 
-/* Terminate the use of po_method_ty methods.  */
-extern void po_scan_end (po_ty *pop);
+/* Terminate the use of abstract_po_reader_class_ty methods.  */
+extern void
+       po_scan_end (abstract_po_reader_ty *pop);
 
-/* Read a PO file from a stream, and dispatch to the various po_method_ty
-   methods.  */
-extern void po_scan (po_ty *pop, FILE *fp, const char *real_filename,
-                    const char *logical_filename);
+/* Read a PO file from a stream, and dispatch to the various
+   abstract_po_reader_class_ty methods.  */
+extern void
+       po_scan (abstract_po_reader_ty *pop, FILE *fp,
+               const char *real_filename, const char *logical_filename);
 
-/* Locate a PO file, open it, read it, dispatching to the various po_method_ty
-   methods, and close it.  */
-extern void po_scan_file (po_ty *pop, const char *filename);
+/* Locate a PO file, open it, read it, dispatching to the various
+   abstract_po_reader_class_ty methods, and close it.  */
+extern void
+       po_scan_file (abstract_po_reader_ty *pop, const char *filename);
 
-/* Call the destructor and deallocate a po_ty (or derived class)
-   instance.  */
-extern void po_free (po_ty *pop);
+/* Call the destructor and deallocate a abstract_po_reader_ty (or derived
+   class) instance.  */
+extern void
+       po_reader_free (abstract_po_reader_ty *pop);
 
 
 /* Callbacks used by po-gram.y or po-hash.y or po-lex.c, indirectly
@@ -159,4 +165,4 @@ extern void po_parse_comment_special (const char *s, bool *fuzzyp,
                                      enum is_format formatp[NFORMATS],
                                      enum is_wrap *wrapp);
 
-#endif /* _PO_H */
+#endif /* _READ_PO_ABSTRACT_H */
index 20cf53999be86826aed9e8cbb36112572ad51452..17e52594e1507fe41192852e1673508807af7b00 100644 (file)
 #include <stdlib.h>
 #include <string.h>
 
-#include "po.h"
 #include "xmalloc.h"
 #include "gettext.h"
 
 #define _(str) gettext (str)
 
 
-/* If nonzero, remember comments for file name and line number for each
-   msgid, if present in the reference input.  Defaults to true.  */
-int line_comment = 1;
+/* ========================================================================= */
+/* Inline functions to invoke the methods.  */
 
-/* If false, duplicate msgids in the same domain and file generate an error.
-   If true, such msgids are allowed; the caller should treat them
-   appropriately.  Defaults to false.  */
-bool allow_duplicates = false;
+static inline void
+call_set_domain (struct default_po_reader_ty *this, char *name)
+{
+  default_po_reader_class_ty *methods =
+    (default_po_reader_class_ty *) this->methods;
 
+  if (methods->set_domain)
+    methods->set_domain (this, name);
+}
 
-/* This structure defines a derived class of the po_ty class.  (See
-   po.h for an explanation.)  */
-typedef struct readall_class_ty readall_class_ty;
-struct readall_class_ty
+static inline void
+call_add_message (struct default_po_reader_ty *this,
+                 char *msgid, lex_pos_ty *msgid_pos, char *msgid_plural,
+                 char *msgstr, size_t msgstr_len, lex_pos_ty *msgstr_pos,
+                 bool obsolete)
 {
-  /* inherited instance variables, etc.  */
-  PO_BASE_TY
+  default_po_reader_class_ty *methods =
+    (default_po_reader_class_ty *) this->methods;
 
-  /* List of messages already appeared in the current file.  */
-  msgdomain_list_ty *mdlp;
+  if (methods->add_message)
+    methods->add_message (this, msgid, msgid_pos, msgid_plural,
+                         msgstr, msgstr_len, msgstr_pos, obsolete);
+}
 
-  /* Name of domain we are currently examining.  */
-  char *domain;
+static inline void
+call_frob_new_message (struct default_po_reader_ty *this, message_ty *mp,
+                      const lex_pos_ty *msgid_pos,
+                      const lex_pos_ty *msgstr_pos)
+{
+  default_po_reader_class_ty *methods =
+    (default_po_reader_class_ty *) this->methods;
 
-  /* List of messages belonging to the current domain.  */
-  message_list_ty *mlp;
+  if (methods->frob_new_message)
+    methods->frob_new_message (this, mp, msgid_pos, msgstr_pos);
+}
 
-  /* Accumulate comments for next message directive.  */
-  string_list_ty *comment;
-  string_list_ty *comment_dot;
 
-  /* Flags transported in special comments.  */
-  bool is_fuzzy;
-  enum is_format is_format[NFORMATS];
-  enum is_wrap do_wrap;
+/* ========================================================================= */
+/* Implementation of default_po_reader_ty's methods.  */
 
-  /* Accumulate filepos comments for the next message directive.  */
-  size_t filepos_count;
-  lex_pos_ty *filepos;
-};
+
+/* Implementation of methods declared in the superclass.  */
 
 
 /* Prepare for first message.  */
-static void
-readall_constructor (po_ty *that)
+void
+default_constructor (abstract_po_reader_ty *that)
 {
-  readall_class_ty *this = (readall_class_ty *) that;
+  default_po_reader_ty *this = (default_po_reader_ty *) that;
   size_t i;
 
-  this->mdlp = msgdomain_list_alloc (!allow_duplicates);
   this->domain = MESSAGE_DOMAIN_DEFAULT;
-  this->mlp = msgdomain_list_sublist (this->mdlp, this->domain, true);
   this->comment = NULL;
   this->comment_dot = NULL;
   this->filepos_count = 0;
@@ -97,140 +99,106 @@ readall_constructor (po_ty *that)
 }
 
 
-static void
-readall_destructor (po_ty *that)
+void
+default_destructor (abstract_po_reader_ty *that)
 {
-  readall_class_ty *this = (readall_class_ty *) that;
-  size_t j;
+  default_po_reader_ty *this = (default_po_reader_ty *) that;
 
   /* Do not free this->mdlp and this->mlp.  */
-  if (this->comment != NULL)
-    string_list_free (this->comment);
-  if (this->comment_dot != NULL)
-    string_list_free (this->comment_dot);
-  for (j = 0; j < this->filepos_count; ++j)
-    free (this->filepos[j].file_name);
-  if (this->filepos != NULL)
-    free (this->filepos);
+  if (this->handle_comments)
+    {
+      if (this->comment != NULL)
+       string_list_free (this->comment);
+      if (this->comment_dot != NULL)
+       string_list_free (this->comment_dot);
+    }
+  if (this->handle_filepos_comments)
+    {
+      size_t j;
+
+      for (j = 0; j < this->filepos_count; ++j)
+       free (this->filepos[j].file_name);
+      if (this->filepos != NULL)
+       free (this->filepos);
+    }
 }
 
 
-/* Process 'domain' directive from .po file.  */
-static void
-readall_directive_domain (po_ty *that, char *name)
+void
+default_parse_brief (abstract_po_reader_ty *that)
 {
-  size_t j;
+  /* We need to parse comments, because even if this->handle_comments and
+     this->handle_filepos_comments are false, we need to know which messages
+     are fuzzy.  */
+  po_lex_pass_comments (true);
+}
 
-  readall_class_ty *this = (readall_class_ty *) that;
-  /* Override current domain name.  Don't free memory.  */
-  this->domain = name;
 
-  /* If there are accumulated comments, throw them away, they are
-     probably part of the file header, or about the domain directive,
-     and will be unrelated to the next message.  */
-  if (this->comment != NULL)
-    {
-      string_list_free (this->comment);
-      this->comment = NULL;
-    }
-  if (this->comment_dot != NULL)
-    {
-      string_list_free (this->comment_dot);
-      this->comment_dot = NULL;
-    }
-  for (j = 0; j < this->filepos_count; ++j)
-    free (this->filepos[j].file_name);
-  if (this->filepos != NULL)
-    free (this->filepos);
-  this->filepos_count = 0;
-  this->filepos = NULL;
+void
+default_parse_debrief (abstract_po_reader_ty *that)
+{
 }
 
 
-/* Process 'msgid'/'msgstr' pair from .po file.  */
+/* Add the accumulated comments to the message.  */
 static void
-readall_directive_message (po_ty *that,
-                          char *msgid,
-                          lex_pos_ty *msgid_pos,
-                          char *msgid_plural,
-                          char *msgstr, size_t msgstr_len,
-                          lex_pos_ty *msgstr_pos,
-                          bool obsolete)
+default_copy_comment_state (default_po_reader_ty *this, message_ty *mp)
 {
-  readall_class_ty *this = (readall_class_ty *) that;
-  message_ty *mp;
   size_t j, i;
 
-  /* Select the appropriate sublist of this->mdlp.  */
-  this->mlp = msgdomain_list_sublist (this->mdlp, this->domain, true);
-
-  if (allow_duplicates && msgid[0] != '\0')
-    /* Doesn't matter if this message ID has been seen before.  */
-    mp = NULL;
-  else
-    /* See if this message ID has been seen before.  */
-    mp = message_list_search (this->mlp, msgid);
-
-  if (mp)
-    {
-      po_gram_error_at_line (msgid_pos, _("duplicate message definition"));
-      po_gram_error_at_line (&mp->pos, _("\
-...this is the location of the first definition"));
-      free (msgstr);
-      free (msgid);
-    }
-  else
-    {
-      mp = message_alloc (msgid, msgid_plural, msgstr, msgstr_len, msgstr_pos);
-      message_list_append (this->mlp, mp);
-      mp->obsolete = obsolete;
-    }
-
-  /* Add the accumulated comments to the message.  */
-  if (this->comment != NULL)
-    {
-      for (j = 0; j < this->comment->nitems; ++j)
-       message_comment_append (mp, this->comment->item[j]);
-    }
-  if (this->comment_dot != NULL)
+  if (this->handle_comments)
     {
-      for (j = 0; j < this->comment_dot->nitems; ++j)
-       message_comment_dot_append (mp, this->comment_dot->item[j]);
+      if (this->comment != NULL)
+       for (j = 0; j < this->comment->nitems; ++j)
+         message_comment_append (mp, this->comment->item[j]);
+      if (this->comment_dot != NULL)
+       for (j = 0; j < this->comment_dot->nitems; ++j)
+         message_comment_dot_append (mp, this->comment_dot->item[j]);
     }
-  for (j = 0; j < this->filepos_count; ++j)
+  if (this->handle_filepos_comments)
     {
-      lex_pos_ty *pp;
+      for (j = 0; j < this->filepos_count; ++j)
+       {
+         lex_pos_ty *pp;
 
-      pp = &this->filepos[j];
-      message_comment_filepos (mp, pp->file_name, pp->line_number);
+         pp = &this->filepos[j];
+         message_comment_filepos (mp, pp->file_name, pp->line_number);
+       }
     }
   mp->is_fuzzy = this->is_fuzzy;
   for (i = 0; i < NFORMATS; i++)
     mp->is_format[i] = this->is_format[i];
   mp->do_wrap = this->do_wrap;
+}
 
-  /* Prepare for next message.  */
-  if (this->comment != NULL)
-    {
-      string_list_free (this->comment);
-      this->comment = NULL;
-    }
-  if (this->comment_dot != NULL)
+
+static void
+default_reset_comment_state (default_po_reader_ty *this)
+{
+  size_t j, i;
+
+  if (this->handle_comments)
     {
-      string_list_free (this->comment_dot);
-      this->comment_dot = NULL;
+      if (this->comment != NULL)
+       {
+         string_list_free (this->comment);
+         this->comment = NULL;
+       }
+      if (this->comment_dot != NULL)
+       {
+         string_list_free (this->comment_dot);
+         this->comment_dot = NULL;
+       }
     }
-  for (j = 0; j < this->filepos_count; ++j)
+  if (this->handle_filepos_comments)
     {
-      lex_pos_ty *pp;
-
-      pp = &this->filepos[j];
-      free (pp->file_name);
+      for (j = 0; j < this->filepos_count; ++j)
+       free (this->filepos[j].file_name);
+      if (this->filepos != NULL)
+       free (this->filepos);
+      this->filepos_count = 0;
+      this->filepos = NULL;
     }
-  if (this->filepos != NULL)
-    free (this->filepos);
-  this->filepos_count = 0;
-  this->filepos = NULL;
   this->is_fuzzy = false;
   for (i = 0; i < NFORMATS; i++)
     this->is_format[i] = undecided;
@@ -238,60 +206,177 @@ readall_directive_message (po_ty *that,
 }
 
 
-static void
-readall_parse_brief (po_ty *that)
+/* Process 'domain' directive from .po file.  */
+void
+default_directive_domain (abstract_po_reader_ty *that, char *name)
 {
-  po_lex_pass_comments (true);
+  default_po_reader_ty *this = (default_po_reader_ty *) that;
+
+  call_set_domain (this, name);
+
+  /* If there are accumulated comments, throw them away, they are
+     probably part of the file header, or about the domain directive,
+     and will be unrelated to the next message.  */
+  default_reset_comment_state (this);
 }
 
 
-static void
-readall_comment (po_ty *that, const char *s)
+/* Process 'msgid'/'msgstr' pair from .po file.  */
+void
+default_directive_message (abstract_po_reader_ty *that,
+                          char *msgid,
+                          lex_pos_ty *msgid_pos,
+                          char *msgid_plural,
+                          char *msgstr, size_t msgstr_len,
+                          lex_pos_ty *msgstr_pos,
+                          bool obsolete)
 {
-  readall_class_ty *this = (readall_class_ty *) that;
+  default_po_reader_ty *this = (default_po_reader_ty *) that;
+
+  call_add_message (this, msgid, msgid_pos, msgid_plural,
+                   msgstr, msgstr_len, msgstr_pos, obsolete);
 
-  if (this->comment == NULL)
-    this->comment = string_list_alloc ();
-  string_list_append (this->comment, s);
+  /* Prepare for next message.  */
+  default_reset_comment_state (this);
 }
 
 
-static void
-readall_comment_dot (po_ty *that, const char *s)
+void
+default_comment (abstract_po_reader_ty *that, const char *s)
+{
+  default_po_reader_ty *this = (default_po_reader_ty *) that;
+
+  if (this->handle_comments)
+    {
+      if (this->comment == NULL)
+       this->comment = string_list_alloc ();
+      string_list_append (this->comment, s);
+    }
+}
+
+
+void
+default_comment_dot (abstract_po_reader_ty *that, const char *s)
 {
-  readall_class_ty *this = (readall_class_ty *) that;
+  default_po_reader_ty *this = (default_po_reader_ty *) that;
 
-  if (this->comment_dot == NULL)
-    this->comment_dot = string_list_alloc ();
-  string_list_append (this->comment_dot, s);
+  if (this->handle_comments)
+    {
+      if (this->comment_dot == NULL)
+       this->comment_dot = string_list_alloc ();
+      string_list_append (this->comment_dot, s);
+    }
+}
+
+
+void
+default_comment_filepos (abstract_po_reader_ty *that,
+                        const char *name, size_t line)
+{
+  default_po_reader_ty *this = (default_po_reader_ty *) that;
+
+  if (this->handle_filepos_comments)
+    {
+      size_t nbytes;
+      lex_pos_ty *pp;
+
+      nbytes = (this->filepos_count + 1) * sizeof (this->filepos[0]);
+      this->filepos = xrealloc (this->filepos, nbytes);
+      pp = &this->filepos[this->filepos_count++];
+      pp->file_name = xstrdup (name);
+      pp->line_number = line;
+    }
 }
 
 
 /* Test for '#, fuzzy' comments and warn.  */
-static void
-readall_comment_special (po_ty *that, const char *s)
+void
+default_comment_special (abstract_po_reader_ty *that, const char *s)
 {
-  readall_class_ty *this = (readall_class_ty *) that;
+  default_po_reader_ty *this = (default_po_reader_ty *) that;
 
   po_parse_comment_special (s, &this->is_fuzzy, this->is_format,
                            &this->do_wrap);
 }
 
 
-static void
-readall_comment_filepos (po_ty *that, const char *name, size_t line)
+/* Default implementation of methods not inherited from the superclass.  */
+
+
+void
+default_set_domain (default_po_reader_ty *this, char *name)
+{
+  if (this->allow_domain_directives)
+    /* Override current domain name.  Don't free memory.  */
+    this->domain = name;
+  else
+    {
+      po_gram_error_at_line (&gram_pos,
+                            _("this file may not contain domain directives"));
+
+      /* NAME was allocated in po-gram-gen.y but is not used anywhere.  */
+      free (name);
+    }
+}
+
+void
+default_add_message (default_po_reader_ty *this,
+                    char *msgid,
+                    lex_pos_ty *msgid_pos,
+                    char *msgid_plural,
+                    char *msgstr, size_t msgstr_len,
+                    lex_pos_ty *msgstr_pos,
+                    bool obsolete)
 {
-  readall_class_ty *this = (readall_class_ty *) that;
-  size_t nbytes;
-  lex_pos_ty *pp;
-
-  if (!line_comment)
-    return;
-  nbytes = (this->filepos_count + 1) * sizeof (this->filepos[0]);
-  this->filepos = xrealloc (this->filepos, nbytes);
-  pp = &this->filepos[this->filepos_count++];
-  pp->file_name = xstrdup (name);
-  pp->line_number = line;
+  message_ty *mp;
+
+  if (this->mdlp != NULL)
+    /* Select the appropriate sublist of this->mdlp.  */
+    this->mlp = msgdomain_list_sublist (this->mdlp, this->domain, true);
+
+  if (this->allow_duplicates && msgid[0] != '\0')
+    /* Doesn't matter if this message ID has been seen before.  */
+    mp = NULL;
+  else
+    /* See if this message ID has been seen before.  */
+    mp = message_list_search (this->mlp, msgid);
+
+  if (mp)
+    {
+      if (!(this->allow_duplicates_if_same_msgstr
+           && msgstr_len == mp->msgstr_len
+           && memcmp (msgstr, mp->msgstr, msgstr_len) == 0))
+       {
+         /* We give a fatal error about this, regardless whether the
+            translations are equal or different.  This is for consistency
+            with msgmerge, msgcat and others.  The user can use the
+            msguniq program to get rid of duplicates.  */
+         po_gram_error_at_line (msgid_pos, _("duplicate message definition"));
+         po_gram_error_at_line (&mp->pos, _("\
+...this is the location of the first definition"));
+       }
+      /* We don't need the just constructed entries' parameter string
+        (allocated in po-gram-gen.y).  */
+      free (msgstr);
+      free (msgid);
+
+      /* Add the accumulated comments to the message.  */
+      default_copy_comment_state (this, mp);
+    }
+  else
+    {
+      /* Construct message to add to the list.
+        Obsolete message go into the list at least for duplicate checking.
+        It's the caller's responsibility to ignore obsolete messages when
+        appropriate.  */
+      mp = message_alloc (msgid, msgid_plural, msgstr, msgstr_len, msgstr_pos);
+      mp->obsolete = obsolete;
+      default_copy_comment_state (this, mp);
+
+      call_frob_new_message (this, mp, msgid_pos, msgstr_pos);
+
+      message_list_append (this->mlp, mp);
+    }
 }
 
 
@@ -301,33 +386,66 @@ readall_comment_filepos (po_ty *that, const char *name, size_t line)
    and all actions resulting from the parse will be through
    invocations of method functions of that object.  */
 
-static po_method_ty readall_methods =
+static default_po_reader_class_ty default_methods =
 {
-  sizeof (readall_class_ty),
-  readall_constructor,
-  readall_destructor,
-  readall_directive_domain,
-  readall_directive_message,
-  readall_parse_brief,
-  NULL, /* parse_debrief */
-  readall_comment,
-  readall_comment_dot,
-  readall_comment_filepos,
-  readall_comment_special
+  {
+    sizeof (default_po_reader_ty),
+    default_constructor,
+    default_destructor,
+    default_parse_brief,
+    default_parse_debrief,
+    default_directive_domain,
+    default_directive_message,
+    default_comment,
+    default_comment_dot,
+    default_comment_filepos,
+    default_comment_special
+  },
+  default_set_domain, /* set_domain */
+  default_add_message, /* add_message */
+  NULL /* frob_new_message */
 };
 
 
+default_po_reader_ty *
+default_po_reader_alloc (default_po_reader_class_ty *method_table)
+{
+  return (default_po_reader_ty *) po_reader_alloc (&method_table->super);
+}
+
+
+/* ========================================================================= */
+/* Exported functions.  */
+
+
+/* If nonzero, remember comments for file name and line number for each
+   msgid, if present in the reference input.  Defaults to true.  */
+int line_comment = 1;
+
+/* If false, duplicate msgids in the same domain and file generate an error.
+   If true, such msgids are allowed; the caller should treat them
+   appropriately.  Defaults to false.  */
+bool allow_duplicates = false;
+
+
 msgdomain_list_ty *
 read_po (FILE *fp, const char *real_filename, const char *logical_filename)
 {
-  po_ty *pop;
+  default_po_reader_ty *pop;
   msgdomain_list_ty *mdlp;
 
-  pop = po_alloc (&readall_methods);
+  pop = default_po_reader_alloc (&default_methods);
+  pop->handle_comments = true;
+  pop->handle_filepos_comments = (line_comment != 0);
+  pop->allow_domain_directives = true;
+  pop->allow_duplicates = allow_duplicates;
+  pop->allow_duplicates_if_same_msgstr = false;
+  pop->mdlp = msgdomain_list_alloc (!pop->allow_duplicates);
+  pop->mlp = msgdomain_list_sublist (pop->mdlp, pop->domain, true);
   po_lex_pass_obsolete_entries (true);
-  po_scan (pop, fp, real_filename, logical_filename);
-  mdlp = ((readall_class_ty *) pop)->mdlp;
-  po_free (pop);
+  po_scan ((abstract_po_reader_ty *) pop, fp, real_filename, logical_filename);
+  mdlp = pop->mdlp;
+  po_reader_free ((abstract_po_reader_ty *) pop);
   return mdlp;
 }
 
@@ -335,13 +453,20 @@ read_po (FILE *fp, const char *real_filename, const char *logical_filename)
 msgdomain_list_ty *
 read_po_file (const char *filename)
 {
-  po_ty *pop;
+  default_po_reader_ty *pop;
   msgdomain_list_ty *mdlp;
 
-  pop = po_alloc (&readall_methods);
+  pop = default_po_reader_alloc (&default_methods);
+  pop->handle_comments = true;
+  pop->handle_filepos_comments = (line_comment != 0);
+  pop->allow_domain_directives = true;
+  pop->allow_duplicates = allow_duplicates;
+  pop->allow_duplicates_if_same_msgstr = false;
+  pop->mdlp = msgdomain_list_alloc (!pop->allow_duplicates);
+  pop->mlp = msgdomain_list_sublist (pop->mdlp, pop->domain, true);
   po_lex_pass_obsolete_entries (true);
-  po_scan_file (pop, filename);
-  mdlp = ((readall_class_ty *) pop)->mdlp;
-  po_free (pop);
+  po_scan_file ((abstract_po_reader_ty *) pop, filename);
+  mdlp = pop->mdlp;
+  po_reader_free ((abstract_po_reader_ty *) pop);
   return mdlp;
 }
index a75f817a98662bb2a3c1075a0ae9e5d2feab6b59..f2f6807f70da493c5f3a105758c1e2c8539a274a 100644 (file)
 #define _READ_PO_H
 
 #include "message.h"
+#include "read-po-abstract.h"
 
 #include <stdbool.h>
 #include <stdio.h>
 
+/* The following pair of structures cooperate to create a derived class from
+   class abstract_po_reader_ty.  (See read-po-abstract.h for an explanation.)
+   It implements the default behaviour of reading a PO file and converting it
+   to an 'msgdomain_list_ty *'.  */
+
+/* Forward declaration.  */
+struct default_po_reader_ty;
+
+
+typedef struct default_po_reader_class_ty default_po_reader_class_ty;
+struct default_po_reader_class_ty
+{
+  /* Methods inherited from superclass.  */
+  struct abstract_po_reader_class_ty super;
+
+  /* How to change the current domain.  */
+  void (*set_domain) (struct default_po_reader_ty *pop, char *name);
+
+  /* How to add a message to the list.  */
+  void (*add_message) (struct default_po_reader_ty *pop,
+                      char *msgid, lex_pos_ty *msgid_pos, char *msgid_plural,
+                      char *msgstr, size_t msgstr_len, lex_pos_ty *msgstr_pos,
+                      bool obsolete);
+
+  /* How to modify a new message before adding it to the list.  */
+  void (*frob_new_message) (struct default_po_reader_ty *pop, message_ty *mp,
+                           const lex_pos_ty *msgid_pos,
+                           const lex_pos_ty *msgstr_pos);
+};
+
+
+#define DEFAULT_PO_READER_TY \
+  ABSTRACT_PO_READER_TY                                                        \
+                                                                       \
+  /* If true, pay attention to comments and filepos comments.  */      \
+  bool handle_comments;                                                        \
+                                                                       \
+  /* If true, remember comments for file name and line number for each \
+     msgid, if present in the reference input.  */                     \
+  bool handle_filepos_comments;                                                \
+                                                                       \
+  /* If false, domain directives lead to an error messsage.  */                \
+  bool allow_domain_directives;                                                \
+                                                                       \
+  /* If false, duplicate msgids in the same domain and file generate an        \
+     error.  If true, such msgids are allowed; the caller should treat \
+     them appropriately.  */                                           \
+  bool allow_duplicates;                                               \
+                                                                       \
+  /* If true, allow duplicates if they have the same translation.  */  \
+  bool allow_duplicates_if_same_msgstr;                                        \
+                                                                       \
+  /* List of messages already appeared in the current file.  */                \
+  msgdomain_list_ty *mdlp;                                             \
+                                                                       \
+  /* Name of domain we are currently examining.  */                    \
+  const char *domain;                                                  \
+                                                                       \
+  /* List of messages belonging to the current domain.  */             \
+  message_list_ty *mlp;                                                        \
+                                                                       \
+  /* Accumulate comments for next message directive.  */               \
+  string_list_ty *comment;                                             \
+  string_list_ty *comment_dot;                                         \
+                                                                       \
+  /* Accumulate filepos comments for the next message directive.  */   \
+  size_t filepos_count;                                                        \
+  lex_pos_ty *filepos;                                                 \
+                                                                       \
+  /* Flags transported in special comments.  */                                \
+  bool is_fuzzy;                                                       \
+  enum is_format is_format[NFORMATS];                                  \
+  enum is_wrap do_wrap;                                                        \
+
+typedef struct default_po_reader_ty default_po_reader_ty;
+struct default_po_reader_ty
+{
+  DEFAULT_PO_READER_TY
+};
+
+extern void default_constructor (abstract_po_reader_ty *that);
+extern void default_destructor (abstract_po_reader_ty *that);
+extern void default_parse_brief (abstract_po_reader_ty *that);
+extern void default_parse_debrief (abstract_po_reader_ty *that);
+extern void default_directive_domain (abstract_po_reader_ty *that, char *name);
+extern void default_directive_message (abstract_po_reader_ty *that,
+                                      char *msgid,
+                                      lex_pos_ty *msgid_pos,
+                                      char *msgid_plural,
+                                      char *msgstr, size_t msgstr_len,
+                                      lex_pos_ty *msgstr_pos,
+                                      bool obsolete);
+extern void default_comment (abstract_po_reader_ty *that, const char *s);
+extern void default_comment_dot (abstract_po_reader_ty *that, const char *s);
+extern void default_comment_filepos (abstract_po_reader_ty *that,
+                                    const char *name, size_t line);
+extern void default_comment_special (abstract_po_reader_ty *that,
+                                    const char *s);
+extern void default_set_domain (default_po_reader_ty *this, char *name);
+extern void default_add_message (default_po_reader_ty *this,
+                                char *msgid,
+                                lex_pos_ty *msgid_pos,
+                                char *msgid_plural,
+                                char *msgstr, size_t msgstr_len,
+                                lex_pos_ty *msgstr_pos,
+                                bool obsolete);
+
+/* Allocate a fresh default_po_reader_ty (or derived class) instance and
+   call its constructor.  */
+extern default_po_reader_ty *
+       default_po_reader_alloc (default_po_reader_class_ty *method_table);
+
+
 /* If nonzero, remember comments for file name and line number for each
    msgid, if present in the reference input.  Defaults to true.  */
 extern int line_comment;
index 1c458487aa3478a3c0788764ed6b27c27765dece..f513daa38380789dda10be49ef3454d3bce67d5d 100644 (file)
@@ -30,7 +30,7 @@
 #include "x-po.h"
 #include "xgettext.h"
 #include "xmalloc.h"
-#include "po.h"
+#include "read-po.h"
 #include "po-lex.h"
 #include "gettext.h"
 
 #define _(str) gettext (str)
 
 
-typedef struct extract_class_ty extract_class_ty;
-struct extract_class_ty
-{
-  /* Inherited instance variables and methods.  */
-  PO_BASE_TY
-
-  /* Cumulative list of messages.  */
-  message_list_ty *mlp;
-
-  /* Cumulative comments for next message.  */
-  string_list_ty *comment;
-  string_list_ty *comment_dot;
-
-  bool is_fuzzy;
-  enum is_format is_format[NFORMATS];
-  enum is_wrap do_wrap;
-
-  size_t filepos_count;
-  lex_pos_ty *filepos;
-};
-
-
-static void
-extract_constructor (po_ty *that)
-{
-  extract_class_ty *this = (extract_class_ty *) that;
-  size_t i;
-
-  this->mlp = NULL; /* actually set in extract_po, below */
-  this->comment = NULL;
-  this->comment_dot = NULL;
-  this->is_fuzzy = false;
-  for (i = 0; i < NFORMATS; i++)
-    this->is_format[i] = undecided;
-  this->do_wrap = undecided;
-  this->filepos_count = 0;
-  this->filepos = NULL;
-}
-
-
-static void
-extract_directive_domain (po_ty *that, char *name)
-{
-  po_gram_error_at_line (&gram_pos,
-                        _("this file may not contain domain directives"));
-}
-
+/* Define a subclass extract_po_reader_ty of default_po_reader_ty.  */
 
 static void
-extract_directive_message (po_ty *that,
-                          char *msgid,
-                          lex_pos_ty *msgid_pos,
-                          char *msgid_plural,
-                          char *msgstr, size_t msgstr_len,
-                          lex_pos_ty *msgstr_pos,
-                          bool obsolete)
+extract_add_message (default_po_reader_ty *this,
+                    char *msgid,
+                    lex_pos_ty *msgid_pos,
+                    char *msgid_plural,
+                    char *msgstr, size_t msgstr_len,
+                    lex_pos_ty *msgstr_pos,
+                    bool obsolete)
 {
-  extract_class_ty *this = (extract_class_ty *)that;
-  message_ty *mp;
-  size_t j, i;
-
   /* See whether we shall exclude this message.  */
   if (exclude != NULL && message_list_search (exclude, msgid) != NULL)
     goto discard;
@@ -112,150 +62,12 @@ extract_directive_message (po_ty *that,
       discard:
       free (msgid);
       free (msgstr);
-      if (this->comment != NULL)
-       string_list_free (this->comment);
-      if (this->comment_dot != NULL)
-       string_list_free (this->comment_dot);
-      if (this->filepos != NULL)
-       free (this->filepos);
-      this->comment = NULL;
-      this->comment_dot = NULL;
-      this->filepos_count = 0;
-      this->filepos = NULL;
-      this->is_fuzzy = false;
-      for (i = 0; i < NFORMATS; i++)
-       this->is_format[i] = undecided;
-      this->do_wrap = undecided;
       return;
     }
 
-  /* See if this message ID has been seen before.  */
-  mp = message_list_search (this->mlp, msgid);
-  if (mp)
-    {
-      if (msgstr_len != mp->msgstr_len
-         || memcmp (msgstr, mp->msgstr, msgstr_len) != 0)
-       {
-         po_gram_error_at_line (msgid_pos, _("duplicate message definition"));
-         po_gram_error_at_line (&mp->pos, _("\
-...this is the location of the first definition"));
-       }
-      free (msgid);
-      free (msgstr);
-    }
-  else
-    {
-      mp = message_alloc (msgid, msgid_plural, msgstr, msgstr_len, msgstr_pos);
-      message_list_append (this->mlp, mp);
-    }
-
-  /* Add the accumulated comments to the message.  */
-  if (this->comment != NULL)
-    {
-      for (j = 0; j < this->comment->nitems; ++j)
-       message_comment_append (mp, this->comment->item[j]);
-    }
-  if (this->comment_dot != NULL)
-    {
-      for (j = 0; j < this->comment_dot->nitems; ++j)
-       message_comment_dot_append (mp, this->comment_dot->item[j]);
-    }
-  mp->is_fuzzy = this->is_fuzzy;
-  for (i = 0; i < NFORMATS; i++)
-    mp->is_format[i] = this->is_format[i];
-  mp->do_wrap = this->do_wrap;
-  for (j = 0; j < this->filepos_count; ++j)
-    {
-      lex_pos_ty *pp;
-
-      pp = &this->filepos[j];
-      message_comment_filepos (mp, pp->file_name, pp->line_number);
-    }
-
-  /* Prepare for next message.  */
-  if (this->comment != NULL)
-    {
-      string_list_free (this->comment);
-      this->comment = NULL;
-    }
-  if (this->comment_dot != NULL)
-    {
-      string_list_free (this->comment_dot);
-      this->comment_dot = NULL;
-    }
-  for (j = 0; j < this->filepos_count; ++j)
-    {
-      lex_pos_ty *pp;
-
-      pp = &this->filepos[j];
-      free (pp->file_name);
-    }
-  if (this->filepos != NULL)
-    free (this->filepos);
-  this->filepos_count = 0;
-  this->filepos = NULL;
-  this->is_fuzzy = false;
-  for (i = 0; i < NFORMATS; i++)
-    this->is_format[i] = undecided;
-  this->do_wrap = undecided;
-}
-
-
-static void
-extract_parse_brief (po_ty *that)
-{
-  po_lex_pass_comments (true);
-}
-
-
-static void
-extract_comment (po_ty *that, const char *s)
-{
-  extract_class_ty *this = (extract_class_ty *) that;
-
-  if (this->comment == NULL)
-    this->comment = string_list_alloc ();
-  string_list_append (this->comment, s);
-}
-
-
-static void
-extract_comment_dot (po_ty *that, const char *s)
-{
-  extract_class_ty *this = (extract_class_ty *) that;
-
-  if (this->comment_dot == NULL)
-    this->comment_dot = string_list_alloc ();
-  string_list_append (this->comment_dot, s);
-}
-
-
-static void
-extract_comment_filepos (po_ty *that, const char *name, size_t line)
-{
-  extract_class_ty *this = (extract_class_ty *) that;
-  size_t nbytes;
-  lex_pos_ty *pp;
-
-  /* Write line numbers only if -n option is given.  */
-  if (line_comment != 0)
-    {
-      nbytes = (this->filepos_count + 1) * sizeof (this->filepos[0]);
-      this->filepos = xrealloc (this->filepos, nbytes);
-      pp = &this->filepos[this->filepos_count++];
-      pp->file_name = xstrdup (name);
-      pp->line_number = line;
-    }
-}
-
-
-static void
-extract_comment_special (po_ty *that, const char *s)
-{
-  extract_class_ty *this = (extract_class_ty *) that;
-
-  po_parse_comment_special (s, &this->is_fuzzy, this->is_format,
-                           &this->do_wrap);
+  /* Invoke superclass method.  */
+  default_add_message (this, msgid, msgid_pos, msgid_plural,
+                      msgstr, msgstr_len, msgstr_pos, obsolete);
 }
 
 
@@ -265,19 +77,24 @@ extract_comment_special (po_ty *that, const char *s)
    and all actions resulting from the parse will be through
    invocations of method functions of that object.  */
 
-static po_method_ty extract_methods =
+static default_po_reader_class_ty extract_methods =
 {
-  sizeof (extract_class_ty),
-  extract_constructor,
-  NULL, /* destructor */
-  extract_directive_domain,
-  extract_directive_message,
-  extract_parse_brief,
-  NULL, /* parse_debrief */
-  extract_comment,
-  extract_comment_dot,
-  extract_comment_filepos,
-  extract_comment_special
+  {
+    sizeof (default_po_reader_ty),
+    default_constructor,
+    default_destructor,
+    default_parse_brief,
+    default_parse_debrief,
+    default_directive_domain,
+    default_directive_message,
+    default_comment,
+    default_comment_dot,
+    default_comment_filepos,
+    default_comment_special
+  },
+  default_set_domain, /* set_domain */
+  extract_add_message, /* add_message */
+  NULL /* frob_new_message */
 };
 
 
@@ -286,8 +103,16 @@ extract_po (FILE *fp,
            const char *real_filename, const char *logical_filename,
            msgdomain_list_ty *mdlp)
 {
-  po_ty *pop = po_alloc (&extract_methods);
-  ((extract_class_ty *) pop)->mlp = mdlp->item[0]->messages;
-  po_scan (pop, fp, real_filename, logical_filename);
-  po_free (pop);
+  default_po_reader_ty *pop;
+
+  pop = default_po_reader_alloc (&extract_methods);
+  pop->handle_comments = true;
+  pop->handle_filepos_comments = (line_comment != 0);
+  pop->allow_domain_directives = false;
+  pop->allow_duplicates = false;
+  pop->allow_duplicates_if_same_msgstr = true;
+  pop->mdlp = NULL;
+  pop->mlp = mdlp->item[0]->messages;
+  po_scan ((abstract_po_reader_ty *) pop, fp, real_filename, logical_filename);
+  po_reader_free ((abstract_po_reader_ty *) pop);
 }
index 1eae3e300347ed36a5c1ada6d11e1433980a89e4..1e26d1f813e2252b61544ed8fa9502ed761f0e30 100644 (file)
@@ -47,7 +47,7 @@
 #include "pathname.h"
 #include "strcase.h"
 #include "stpcpy.h"
-#include "po.h"
+#include "read-po-abstract.h"
 #include "message.h"
 #include "po-charset.h"
 #include "msgl-iconv.h"
@@ -713,7 +713,7 @@ Informative output:\n\
 
 
 static void
-exclude_directive_domain (po_ty *pop, char *name)
+exclude_directive_domain (abstract_po_reader_ty *pop, char *name)
 {
   po_gram_error_at_line (&gram_pos,
                         _("this file may not contain domain directives"));
@@ -721,7 +721,7 @@ exclude_directive_domain (po_ty *pop, char *name)
 
 
 static void
-exclude_directive_message (po_ty *pop,
+exclude_directive_message (abstract_po_reader_ty *pop,
                           char *msgid,
                           lex_pos_ty *msgid_pos,
                           char *msgid_plural,
@@ -756,15 +756,15 @@ exclude_directive_message (po_ty *pop,
    and all actions resulting from the parse will be through
    invocations of method functions of that object.  */
 
-static po_method_ty exclude_methods =
+static abstract_po_reader_class_ty exclude_methods =
 {
-  sizeof (po_ty),
+  sizeof (abstract_po_reader_ty),
   NULL, /* constructor */
   NULL, /* destructor */
-  exclude_directive_domain,
-  exclude_directive_message,
   NULL, /* parse_brief */
   NULL, /* parse_debrief */
+  exclude_directive_domain,
+  exclude_directive_message,
   NULL, /* comment */
   NULL, /* comment_dot */
   NULL, /* comment_filepos */
@@ -775,11 +775,11 @@ static po_method_ty exclude_methods =
 static void
 read_exclusion_file (char *file_name)
 {
-  po_ty *pop;
+  abstract_po_reader_ty *pop;
 
-  pop = po_alloc (&exclude_methods);
+  pop = po_reader_alloc (&exclude_methods);
   po_scan_file (pop, file_name);
-  po_free (pop);
+  po_reader_free (pop);
 }