From: Bruno Haible Date: Thu, 24 Apr 2003 10:55:35 +0000 (+0000) Subject: Unify three PO file parsers into a single one, as far as possible. X-Git-Tag: v0.12~69 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=82f2b974b2d14c448e007d50e0a73430e86f1c7c;p=thirdparty%2Fgettext.git Unify three PO file parsers into a single one, as far as possible. --- diff --git a/gettext-tools/src/ChangeLog b/gettext-tools/src/ChangeLog index 802ed8334..ec96ab1d4 100644 --- a/gettext-tools/src/ChangeLog +++ b/gettext-tools/src/ChangeLog @@ -1,3 +1,96 @@ +2003-04-13 Bruno Haible + + 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 * write-po.h (message_print_comment, message_print_comment_dot, diff --git a/gettext-tools/src/FILES b/gettext-tools/src/FILES index 1a9324098..d8b35fa2f 100644 --- a/gettext-tools/src/FILES +++ b/gettext-tools/src/FILES @@ -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 diff --git a/gettext-tools/src/Makefile.am b/gettext-tools/src/Makefile.am index 0adb58985..15103e822 100644 --- a/gettext-tools/src/Makefile.am +++ b/gettext-tools/src/Makefile.am @@ -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. diff --git a/gettext-tools/src/Makefile.msvc b/gettext-tools/src/Makefile.msvc index d776e00b8..a824f10f5 100644 --- a/gettext-tools/src/Makefile.msvc +++ b/gettext-tools/src/Makefile.msvc @@ -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 diff --git a/gettext-tools/src/Makefile.vms b/gettext-tools/src/Makefile.vms index 979beb566..481c3d384 100644 --- a/gettext-tools/src/Makefile.vms +++ b/gettext-tools/src/Makefile.vms @@ -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 diff --git a/gettext-tools/src/msgcmp.c b/gettext-tools/src/msgcmp.c index 9d60745b6..d1f56e21f 100644 --- a/gettext-tools/src/msgcmp.c +++ b/gettext-tools/src/msgcmp.c @@ -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" diff --git a/gettext-tools/src/msgfmt.c b/gettext-tools/src/msgfmt.c index 322f07896..f84458f39 100644 --- a/gettext-tools/src/msgfmt.c +++ b/gettext-tools/src/msgfmt.c @@ -50,7 +50,7 @@ #include "gettext.h" #include "message.h" -#include "po.h" +#include "read-po.h" #define _(str) gettext (str) @@ -70,22 +70,6 @@ # 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); } diff --git a/gettext-tools/src/msgmerge.c b/gettext-tools/src/msgmerge.c index 347704423..6198df402 100644 --- a/gettext-tools/src/msgmerge.c +++ b/gettext-tools/src/msgmerge.c @@ -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" diff --git a/gettext-tools/src/po-gram-gen.y b/gettext-tools/src/po-gram-gen.y index 2850ef90e..355ffba67 100644 --- a/gettext-tools/src/po-gram-gen.y +++ b/gettext-tools/src/po-gram-gen.y @@ -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 @@ -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) diff --git a/gettext-tools/src/po-hash-gen.y b/gettext-tools/src/po-hash-gen.y index 4bdcbc00c..71f40ac04 100644 --- a/gettext-tools/src/po-hash-gen.y +++ b/gettext-tools/src/po-hash-gen.y @@ -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 @@ -40,7 +40,7 @@ #include #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; diff --git a/gettext-tools/src/po-hash.h b/gettext-tools/src/po-hash.h index 7ffc716a9..00218af09 100644 --- a/gettext-tools/src/po-hash.h +++ b/gettext-tools/src/po-hash.h @@ -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 @@ -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 */ diff --git a/gettext-tools/src/po.c b/gettext-tools/src/read-po-abstract.c similarity index 60% rename from gettext-tools/src/po.c rename to gettext-tools/src/read-po-abstract.c index 1d2f4e3a9..666f98c6b 100644 --- a/gettext-tools/src/po.c +++ b/gettext-tools/src/read-po-abstract.c @@ -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 @@ -23,7 +23,7 @@ #endif /* Specification. */ -#include "po.h" +#include "read-po-abstract.h" #include #include @@ -34,49 +34,109 @@ #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); } } diff --git a/gettext-tools/src/po.h b/gettext-tools/src/read-po-abstract.h similarity index 58% rename from gettext-tools/src/po.h rename to gettext-tools/src/read-po-abstract.h index cdab89344..c7bb0cb57 100644 --- a/gettext-tools/src/po.h +++ b/gettext-tools/src/read-po-abstract.h @@ -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 @@ -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" @@ -29,117 +29,123 @@ 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 */ diff --git a/gettext-tools/src/read-po.c b/gettext-tools/src/read-po.c index 20cf53999..17e52594e 100644 --- a/gettext-tools/src/read-po.c +++ b/gettext-tools/src/read-po.c @@ -27,65 +27,67 @@ #include #include -#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; } diff --git a/gettext-tools/src/read-po.h b/gettext-tools/src/read-po.h index a75f817a9..f2f6807f7 100644 --- a/gettext-tools/src/read-po.h +++ b/gettext-tools/src/read-po.h @@ -20,10 +20,124 @@ #define _READ_PO_H #include "message.h" +#include "read-po-abstract.h" #include #include +/* 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; diff --git a/gettext-tools/src/x-po.c b/gettext-tools/src/x-po.c index 1c458487a..f513daa38 100644 --- a/gettext-tools/src/x-po.c +++ b/gettext-tools/src/x-po.c @@ -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" @@ -38,67 +38,17 @@ #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); } diff --git a/gettext-tools/src/xgettext.c b/gettext-tools/src/xgettext.c index 1eae3e300..1e26d1f81 100644 --- a/gettext-tools/src/xgettext.c +++ b/gettext-tools/src/xgettext.c @@ -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); }