From: Bruno Haible Date: Mon, 13 Aug 2001 13:50:43 +0000 (+0000) Subject: Split off the PO file backend of xgettext. X-Git-Tag: v0.11~553 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=539824ee3b29c16790e0747a98ea6f5c33157abb;p=thirdparty%2Fgettext.git Split off the PO file backend of xgettext. --- diff --git a/src/ChangeLog b/src/ChangeLog index 2f81d774d..6f4939506 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,3 +1,43 @@ +2001-07-28 Bruno Haible + + * po-lex.h (lex_start, lex_end): New declarations. + * po-lex.c (lex_start): New function. + (lex_end): New function. + (lex_open): Call lex_start. + (lex_close): Call lex_end. + * open-po.h (open_po_file): Nop. + * open-po.c (open_po_file): Small optimization. + * po.h (po_scan): New declaration. + (po_scan_file): Renamed from po_scan. + * po.c (po_scan): New function. + (po_scan_file): Renamed from po_scan. + * msgcmp.c (grammar): Update po_scan_file call. + * msgfmt.c (grammar): Likewise. + * read-po.c (read_po_file): Likewise. + * x-po.h: New file. + * x-po.c: New file. + (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, + extract_methods): Moved here from xgettext.c. + (extract_po): New function, extracted from read_po_file. + * xgettext.h (line_comment, exclude): New declarations. + * xgettext.c: Include x-po.h. + (line_comment): Make non-static. + (exclude): Likewise. + (main): Update scan_po_file call. + (read_exclusion_file): Update po_scan_file call. + (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, + extract_methods): Move to x-po.c. + (scan_po_file): Renamed from read_po_file. Call xgettext_open and + extract_po. + (language_to_scanner): Use SCANNERS_PO. + (extension_to_language): Use EXTENSIONS_PO. + * Makefile.am (noinst_HEADERS): Add x-po.h. + (xgettext_SOURCES): Add x-po.c. + 2001-07-27 Bruno Haible * x-c.h: New file. diff --git a/src/Makefile.am b/src/Makefile.am index d69db8330..93da414a6 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -26,7 +26,7 @@ msgcat msgcomm msgconv msgen msgexec msggrep msguniq noinst_HEADERS = pos.h message.h po-gram.h po-hash.h po-charset.h po-lex.h \ po.h open-po.h read-po.h str-list.h write-po.h dir-list.h file-list.h \ po-gram-gen.h po-hash-gen.h msgl-charset.h msgl-iconv.h msgl-ascii.h \ -msgl-cat.h xgettext.h x-c.h +msgl-cat.h xgettext.h x-c.h x-po.h EXTRA_DIST = FILES @@ -53,7 +53,7 @@ msgl-ascii.c msgunfmt_SOURCES = message.c msgunfmt.c str-list.c write-po.c msgl-ascii.c xgettext_SOURCES = message.c open-po.c po-gram-gen.y po-hash-gen.y \ po-charset.c po-lex.c po.c str-list.c xgettext.c dir-list.c write-po.c \ -msgl-ascii.c file-list.c x-c.c +msgl-ascii.c file-list.c x-c.c x-po.c msgcat_SOURCES = msgcat.c message.c open-po.c po-gram-gen.y po-hash-gen.y \ po-charset.c po-lex.c po.c read-po.c str-list.c dir-list.c write-po.c \ msgl-ascii.c msgl-iconv.c msgl-cat.c file-list.c diff --git a/src/msgcmp.c b/src/msgcmp.c index 02d88b0a1..039dcc4ca 100644 --- a/src/msgcmp.c +++ b/src/msgcmp.c @@ -459,7 +459,7 @@ grammar (filename) msgdomain_list_ty *mdlp; pop = po_alloc (&compare_methods); - po_scan (pop, filename); + po_scan_file (pop, filename); mdlp = ((compare_class_ty *)pop)->mdlp; po_free (pop); return mdlp; diff --git a/src/msgfmt.c b/src/msgfmt.c index cc2793b4b..28eb777f7 100644 --- a/src/msgfmt.c +++ b/src/msgfmt.c @@ -1104,7 +1104,7 @@ grammar (filename) po_ty *pop; pop = po_alloc (&format_methods); - po_scan (pop, filename); + po_scan_file (pop, filename); po_free (pop); } diff --git a/src/open-po.c b/src/open-po.c index a2fd17ad1..4aed4223e 100644 --- a/src/open-po.c +++ b/src/open-po.c @@ -48,20 +48,22 @@ extern char *xstrdup PARAMS ((const char *string)); /* Open the input file with the name INPUT_NAME. The ending .po is added if necessary. If INPUT_NAME is not an absolute file name and the file is not found, the list of directories in "dir-list.h" is searched. The - file's pathname is returned in *FILE_NAME, for error message purposes. */ + file's pathname is returned in *REAL_FILE_NAME_P, for error message + purposes. */ FILE * -open_po_file (input_name, file_name) +open_po_file (input_name, real_file_name_p) const char *input_name; - char **file_name; + char **real_file_name_p; { static const char *extension[] = { "", ".po", ".pot", }; + char *file_name; FILE *ret_val; int j, k; const char *dir; if (strcmp (input_name, "-") == 0 || strcmp (input_name, "/dev/stdin") == 0) { - *file_name = xstrdup (_("")); + *real_file_name_p = xstrdup (_("")); return stdin; } @@ -71,14 +73,17 @@ open_po_file (input_name, file_name) { for (k = 0; k < SIZEOF (extension); ++k) { - *file_name = concatenated_pathname ("", input_name, extension[k]); + file_name = concatenated_pathname ("", input_name, extension[k]); - ret_val = fopen (*file_name, "r"); + ret_val = fopen (file_name, "r"); if (ret_val != NULL || errno != ENOENT) - /* We found the file. */ - return ret_val; + { + /* We found the file. */ + *real_file_name_p = file_name; + return ret_val; + } - free (*file_name); + free (file_name); } } else @@ -89,18 +94,21 @@ open_po_file (input_name, file_name) for (j = 0; (dir = dir_list_nth (j)) != NULL; ++j) for (k = 0; k < SIZEOF (extension); ++k) { - *file_name = concatenated_pathname (dir, input_name, extension[k]); + file_name = concatenated_pathname (dir, input_name, extension[k]); - ret_val = fopen (*file_name, "r"); + ret_val = fopen (file_name, "r"); if (ret_val != NULL || errno != ENOENT) - return ret_val; + { + *real_file_name_p = file_name; + return ret_val; + } - free (*file_name); + free (file_name); } } /* File does not exist. */ - *file_name = xstrdup (input_name); + *real_file_name_p = xstrdup (input_name); errno = ENOENT; return NULL; } diff --git a/src/open-po.h b/src/open-po.h index 5fd358f1f..8ce0f8784 100644 --- a/src/open-po.h +++ b/src/open-po.h @@ -21,7 +21,9 @@ /* Open the input file with the name INPUT_NAME. The ending .po is added if necessary. If INPUT_NAME is not an absolute file name and the file is not found, the list of directories in "dir-list.h" is searched. The - file's pathname is returned in *FILE_NAME, for error message purposes. */ -extern FILE *open_po_file PARAMS ((const char *input_name, char **file_name)); + file's pathname is returned in *REAL_FILE_NAME_P, for error message + purposes. */ +extern FILE *open_po_file PARAMS ((const char *input_name, + char **real_file_name_p)); #endif /* _OPEN_PO_H */ diff --git a/src/po-lex.c b/src/po-lex.c index c9f8fa688..7437c11d8 100644 --- a/src/po-lex.c +++ b/src/po-lex.c @@ -661,15 +661,17 @@ static int keyword_p PARAMS ((const char *s)); static int control_sequence PARAMS ((void)); -/* Open the PO file FNAME and prepare its lexical analysis. */ +/* Prepare lexical analysis. */ void -lex_open (fname) - const char *fname; +lex_start (fp, real_filename, logical_filename) + FILE *fp; + const char *real_filename; + const char *logical_filename; { - FILE *fp = open_po_file (fname, &gram_pos.file_name); - if (!fp) - error (EXIT_FAILURE, errno, - _("error while opening \"%s\" for reading"), fname); + /* Ignore the logical_filename, because PO file entries already have + their file names attached. But use real_filename for error messages. */ + gram_pos.file_name = xstrdup (real_filename); + mbfile_init (mbf, fp); gram_pos.line_number = 1; @@ -679,19 +681,19 @@ lex_open (fname) po_lex_charset_init (); } - -/* Terminate lexical analysis and close the current PO file. */ -void -lex_close () +/* Terminate lexical analysis. */ +FILE * +lex_end () { + FILE *fp; + if (error_message_count > 0) error (EXIT_FAILURE, 0, ngettext ("found %d fatal error", "found %d fatal errors", error_message_count), error_message_count); - if (mbf->fp != stdin) - fclose (mbf->fp); + fp = mbf->fp; mbf->fp = NULL; gram_pos.file_name = NULL; gram_pos.line_number = 0; @@ -700,6 +702,35 @@ lex_close () error_message_count = 0; po_lex_obsolete = false; po_lex_charset_close (); + + return fp; +} + + +/* Open the PO file FNAME and prepare its lexical analysis. */ +void +lex_open (fname) + const char *fname; +{ + char *real_filename; + FILE *fp = open_po_file (fname, &real_filename); + if (!fp) + error (EXIT_FAILURE, errno, + _("error while opening \"%s\" for reading"), fname); + + lex_start (fp, real_filename, fname); +} + +/* Terminate lexical analysis and close the current PO file. */ +void +lex_close () +{ + FILE *fp; + + fp = lex_end (); + + if (fp != stdin) + fclose (fp); } diff --git a/src/po-lex.h b/src/po-lex.h index da2f5f2c8..d2d2b7418 100644 --- a/src/po-lex.h +++ b/src/po-lex.h @@ -21,6 +21,7 @@ #define _PO_LEX_H #include +#include #include #include "error.h" #include "progname.h" @@ -44,6 +45,13 @@ extern unsigned int gram_max_allowed_errors; extern bool pass_obsolete_entries; +/* Prepare lexical analysis. */ +extern void lex_start PARAMS ((FILE *fp, const char *real_filename, + const char *logical_filename)); + +/* Terminate lexical analysis. */ +extern FILE *lex_end PARAMS ((void)); + /* Open the PO file FNAME and prepare its lexical analysis. */ extern void lex_open PARAMS ((const char *fname)); diff --git a/src/po.c b/src/po.c index 90ac988a0..4d5c45b0d 100644 --- a/src/po.c +++ b/src/po.c @@ -77,7 +77,32 @@ po_free (pop) void -po_scan (pop, filename) +po_scan (pop, fp, real_filename, logical_filename) + po_ty *pop; + FILE *fp; + const char *real_filename; + const char *logical_filename; +{ + extern int po_gram_parse PARAMS ((void)); + + /* The parse will call the po_callback_... functions (see below) + when the various directive are recognised. The callback_arg + variable is used to tell these functions which instance is to + have the relevant method invoked. */ + callback_arg = pop; + + /* Parse the stream's content. */ + lex_start (fp, real_filename, logical_filename); + po_parse_brief (pop); + po_gram_parse (); + po_parse_debrief (pop); + lex_end (); + callback_arg = NULL; +} + + +void +po_scan_file (pop, filename) po_ty *pop; const char *filename; { diff --git a/src/po.h b/src/po.h index 6b4cd67c7..45c2dc631 100644 --- a/src/po.h +++ b/src/po.h @@ -122,8 +122,14 @@ struct po_ty constructor. */ extern po_ty *po_alloc PARAMS ((po_method_ty *jtable)); -/* Read a PO file, and dispatch to the various po_method_ty methods. */ -extern void po_scan PARAMS ((po_ty *pop, const char *filename)); +/* Read a PO file from a stream, and dispatch to the various po_method_ty + methods. */ +extern void po_scan PARAMS ((po_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 PARAMS ((po_ty *pop, const char *filename)); /* Call the destructor and deallocate a po_ty (or derived class) instance. */ diff --git a/src/read-po.c b/src/read-po.c index c736f617d..f0c9ba514 100644 --- a/src/read-po.c +++ b/src/read-po.c @@ -342,7 +342,7 @@ read_po_file (filename) pop = po_alloc (&readall_methods); po_lex_pass_obsolete_entries (true); - po_scan (pop, filename); + po_scan_file (pop, filename); mdlp = ((readall_class_ty *) pop)->mdlp; po_free (pop); return mdlp; diff --git a/src/x-c.c b/src/x-c.c index 395ebee67..07d1be639 100644 --- a/src/x-c.c +++ b/src/x-c.c @@ -1,4 +1,4 @@ -/* GNU gettext - internationalization aids +/* xgettext C/C++/ObjectiveC backend. Copyright (C) 1995-1998, 2000, 2001 Free Software Foundation, Inc. This file was written by Peter Miller diff --git a/src/x-po.c b/src/x-po.c new file mode 100644 index 000000000..474c984f5 --- /dev/null +++ b/src/x-po.c @@ -0,0 +1,311 @@ +/* xgettext PO backend. + Copyright (C) 1995-1998, 2000, 2001 Free Software Foundation, Inc. + + This file was written by Peter Miller + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include +#include + +#include "message.h" +#include "x-po.h" +#include "xgettext.h" +#include "system.h" +#include "po.h" +#include "po-lex.h" +#include "libgettext.h" + +/* A convenience macro. I don't like writing gettext() every time. */ +#define _(str) gettext (str) + + +/* Prototypes for local functions. Needed to ensure compiler checking of + function argument counts despite of K&R C function definition syntax. */ +static void extract_constructor PARAMS ((po_ty *that)); +static void extract_directive_domain PARAMS ((po_ty *that, char *name)); +static void extract_directive_message PARAMS ((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)); +static void extract_parse_brief PARAMS ((po_ty *that)); +static void extract_comment PARAMS ((po_ty *that, const char *s)); +static void extract_comment_dot PARAMS ((po_ty *that, const char *s)); +static void extract_comment_filepos PARAMS ((po_ty *that, const char *name, + int line)); +static void extract_comment_special PARAMS ((po_ty *that, const char *s)); + + +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_c_format is_c_format; + enum is_wrap do_wrap; + + size_t filepos_count; + lex_pos_ty *filepos; +}; + + +static void +extract_constructor (that) + po_ty *that; +{ + extract_class_ty *this = (extract_class_ty *) that; + + this->mlp = NULL; /* actually set in read_po_file, below */ + this->comment = NULL; + this->comment_dot = NULL; + this->is_fuzzy = false; + this->is_c_format = undecided; + this->do_wrap = undecided; + this->filepos_count = 0; + this->filepos = NULL; +} + + +static void +extract_directive_domain (that, name) + po_ty *that; + char *name; +{ + po_gram_error_at_line (&gram_pos, + _("this file may not contain domain directives")); +} + + +static void +extract_directive_message (that, msgid, msgid_pos, msgid_plural, + msgstr, msgstr_len, msgstr_pos, obsolete) + 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_class_ty *this = (extract_class_ty *)that; + message_ty *mp; + size_t j; + + /* See whether we shall exclude this message. */ + if (exclude != NULL && message_list_search (exclude, msgid) != NULL) + goto discard; + + /* If the msgid is the empty string, it is the old header. + Throw it away, we have constructed a new one. */ + if (*msgid == '\0') + { + 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; + this->is_c_format = 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. Clear the + accumulation in preparation for the next message. */ + if (this->comment != NULL) + { + for (j = 0; j < this->comment->nitems; ++j) + message_comment_append (mp, this->comment->item[j]); + string_list_free (this->comment); + this->comment = NULL; + } + if (this->comment_dot != NULL) + { + for (j = 0; j < this->comment_dot->nitems; ++j) + message_comment_dot_append (mp, this->comment_dot->item[j]); + string_list_free (this->comment_dot); + this->comment_dot = NULL; + } + mp->is_fuzzy = this->is_fuzzy; + mp->is_c_format = this->is_c_format; + 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); + free (pp->file_name); + } + if (this->filepos != NULL) + free (this->filepos); + this->filepos_count = 0; + this->filepos = NULL; + this->is_fuzzy = false; + this->is_c_format = undecided; + this->do_wrap = undecided; +} + + +static void +extract_parse_brief (that) + po_ty *that; +{ + po_lex_pass_comments (true); +} + + +static void +extract_comment (that, s) + 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 (that, s) + 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 (that, name, line) + po_ty *that; + const char *name; + int 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 (that, s) + po_ty *that; + const char *s; +{ + extract_class_ty *this = (extract_class_ty *) that; + + if (strstr (s, "fuzzy") != NULL) + this->is_fuzzy = true; + this->is_c_format = parse_c_format_description_string (s); + this->do_wrap = parse_c_width_description_string (s); +} + + +/* So that the one parser can be used for multiple programs, and also + use good data hiding and encapsulation practices, an object + oriented approach has been taken. An object instance is allocated, + and all actions resulting from the parse will be through + invocations of method functions of that object. */ + +static po_method_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 +}; + + +void +extract_po (fp, real_filename, logical_filename, mdlp) + 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); +} diff --git a/src/x-po.h b/src/x-po.h new file mode 100644 index 000000000..f02b610c3 --- /dev/null +++ b/src/x-po.h @@ -0,0 +1,30 @@ +/* xgettext PO backend. + Copyright (C) 2001 Free Software Foundation, Inc. + Written by Bruno Haible , 2001. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + + +#define EXTENSIONS_PO \ + { "po", "PO", }, \ + { "pot", "PO", }, \ + +#define SCANNERS_PO \ + { "PO", scan_po_file, }, \ + +/* Scan a PO file and add its translatable strings to mdlp. */ +extern void extract_po PARAMS ((FILE *fp, const char *real_filename, + const char *logical_filename, + msgdomain_list_ty *mdlp)); diff --git a/src/xgettext.c b/src/xgettext.c index 4d90f7d4c..415951be6 100644 --- a/src/xgettext.c +++ b/src/xgettext.c @@ -58,13 +58,14 @@ struct passwd *getpwuid (); #include "x-c.h" +#include "x-po.h" /* If nonzero add all comments immediately preceding one of the keywords. */ static bool add_all_comments = false; /* If nonzero add comments for file name and line number for each msgid. */ -static int line_comment; +int line_comment; /* Tag used in comment of prevailing domain. */ static char *comment_tag; @@ -77,7 +78,7 @@ static const char *default_domain; static int do_debug; /* Content of .po files with symbols to be excluded. */ -static message_list_ty *exclude; +message_list_ty *exclude; /* Force output of PO file even if empty. */ static int force_po; @@ -155,21 +156,7 @@ static FILE *xgettext_open PARAMS ((const char *fn, char **logical_file_name_p, char **real_file_name_p)); static void scan_c_file PARAMS ((const char *file_name, msgdomain_list_ty *mdlp)); -static void extract_constructor PARAMS ((po_ty *that)); -static void extract_directive_domain PARAMS ((po_ty *that, char *name)); -static void extract_directive_message PARAMS ((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)); -static void extract_parse_brief PARAMS ((po_ty *that)); -static void extract_comment PARAMS ((po_ty *that, const char *s)); -static void extract_comment_dot PARAMS ((po_ty *that, const char *s)); -static void extract_comment_filepos PARAMS ((po_ty *that, const char *name, - int line)); -static void extract_comment_special PARAMS ((po_ty *that, const char *s)); -static void read_po_file PARAMS ((const char *file_name, +static void scan_po_file PARAMS ((const char *file_name, msgdomain_list_ty *mdlp)); static long difftm PARAMS ((const struct tm *a, const struct tm *b)); static message_ty *construct_header PARAMS ((void)); @@ -439,7 +426,7 @@ warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\ /* Read in the old messages, so that we can add to them. */ if (join_existing) - read_po_file (file_name, mdlp); + scan_po_file (file_name, mdlp); /* Process all input files. */ for (cnt = 0; cnt < file_list->nitems; ++cnt) @@ -673,7 +660,7 @@ read_exclusion_file (file_name) po_ty *pop; pop = po_alloc (&exclude_methods); - po_scan (pop, file_name); + po_scan_file (pop, file_name); po_free (pop); } @@ -941,258 +928,23 @@ scan_c_file (file_name, mdlp) } -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_c_format is_c_format; - enum is_wrap do_wrap; - - size_t filepos_count; - lex_pos_ty *filepos; -}; - - -static void -extract_constructor (that) - po_ty *that; -{ - extract_class_ty *this = (extract_class_ty *) that; - - this->mlp = NULL; /* actually set in read_po_file, below */ - this->comment = NULL; - this->comment_dot = NULL; - this->is_fuzzy = false; - this->is_c_format = undecided; - this->do_wrap = undecided; - this->filepos_count = 0; - this->filepos = NULL; -} - - -static void -extract_directive_domain (that, name) - po_ty *that; - char *name; -{ - po_gram_error_at_line (&gram_pos, - _("this file may not contain domain directives")); -} - - -static void -extract_directive_message (that, msgid, msgid_pos, msgid_plural, - msgstr, msgstr_len, msgstr_pos, obsolete) - 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_class_ty *this = (extract_class_ty *)that; - message_ty *mp; - size_t j; - - /* See whether we shall exclude this message. */ - if (exclude != NULL && message_list_search (exclude, msgid) != NULL) - goto discard; - - /* If the msgid is the empty string, it is the old header. - Throw it away, we have constructed a new one. */ - if (*msgid == '\0') - { - 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; - this->is_c_format = 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. Clear the - accumulation in preparation for the next message. */ - if (this->comment != NULL) - { - for (j = 0; j < this->comment->nitems; ++j) - message_comment_append (mp, this->comment->item[j]); - string_list_free (this->comment); - this->comment = NULL; - } - if (this->comment_dot != NULL) - { - for (j = 0; j < this->comment_dot->nitems; ++j) - message_comment_dot_append (mp, this->comment_dot->item[j]); - string_list_free (this->comment_dot); - this->comment_dot = NULL; - } - mp->is_fuzzy = this->is_fuzzy; - mp->is_c_format = this->is_c_format; - 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); - free (pp->file_name); - } - if (this->filepos != NULL) - free (this->filepos); - this->filepos_count = 0; - this->filepos = NULL; - this->is_fuzzy = false; - this->is_c_format = undecided; - this->do_wrap = undecided; -} - - -static void -extract_parse_brief (that) - po_ty *that; -{ - po_lex_pass_comments (true); -} - - -static void -extract_comment (that, s) - 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 (that, s) - 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 (that, name, line) - po_ty *that; - const char *name; - int 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 (that, s) - po_ty *that; - const char *s; -{ - extract_class_ty *this = (extract_class_ty *) that; - - if (strstr (s, "fuzzy") != NULL) - this->is_fuzzy = true; - this->is_c_format = parse_c_format_description_string (s); - this->do_wrap = parse_c_width_description_string (s); -} - - -/* So that the one parser can be used for multiple programs, and also - use good data hiding and encapsulation practices, an object - oriented approach has been taken. An object instance is allocated, - and all actions resulting from the parse will be through - invocations of method functions of that object. */ - -static po_method_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 -}; - - /* Read the contents of the specified .po file into a message list. */ static void -read_po_file (file_name, mdlp) +scan_po_file (file_name, mdlp) const char *file_name; msgdomain_list_ty *mdlp; { - po_ty *pop = po_alloc (&extract_methods); - ((extract_class_ty *) pop)->mlp = mdlp->item[0]->messages; - po_scan (pop, file_name); - po_free (pop); + char *logical_filename; + char *real_filename; + FILE *fp = xgettext_open (file_name, &logical_filename, &real_filename); + + extract_po (fp, real_filename, logical_filename, mdlp); + + if (fp != stdin) + fclose (fp); + free (logical_filename); + free (real_filename); } @@ -1329,7 +1081,7 @@ language_to_scanner (name) static table_ty table[] = { SCANNERS_C - { "PO", read_po_file, }, + SCANNERS_PO /* Here will follow more languages and their scanners: awk, perl, etc... Make sure new scanners honor the --exlude-file option. */ }; @@ -1359,9 +1111,7 @@ extension_to_language (extension) static table_ty table[] = { EXTENSIONS_C - { "po", "PO", }, - { "pot", "PO", }, - { "pox", "PO", }, + EXTENSIONS_PO /* Here will follow more file extensions: sh, pl, tcl, lisp ... */ }; diff --git a/src/xgettext.h b/src/xgettext.h index 5437d7d1c..80e9cc460 100644 --- a/src/xgettext.h +++ b/src/xgettext.h @@ -24,6 +24,10 @@ #include "message.h" #include "pos.h" +extern int line_comment; + +extern message_list_ty *exclude; + extern void xgettext_comment_add PARAMS ((const char *str)); extern const char *xgettext_comment PARAMS ((size_t n)); extern void xgettext_comment_reset PARAMS ((void));