]> git.ipfire.org Git - thirdparty/gettext.git/commitdiff
Split off the PO file backend of xgettext.
authorBruno Haible <bruno@clisp.org>
Mon, 13 Aug 2001 13:50:43 +0000 (13:50 +0000)
committerBruno Haible <bruno@clisp.org>
Mon, 13 Aug 2001 13:50:43 +0000 (13:50 +0000)
16 files changed:
src/ChangeLog
src/Makefile.am
src/msgcmp.c
src/msgfmt.c
src/open-po.c
src/open-po.h
src/po-lex.c
src/po-lex.h
src/po.c
src/po.h
src/read-po.c
src/x-c.c
src/x-po.c [new file with mode: 0644]
src/x-po.h [new file with mode: 0644]
src/xgettext.c
src/xgettext.h

index 2f81d774d9565e4f27e8c852f7b7aa4b5aeea6c7..6f4939506b1ea5ea72736a6a828ff6bddcd1106d 100644 (file)
@@ -1,3 +1,43 @@
+2001-07-28  Bruno Haible  <haible@clisp.cons.org>
+
+       * 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  <haible@clisp.cons.org>
 
        * x-c.h: New file.
index d69db8330da017dc1374667cab524adf618e7ff2..93da414a67f4d135e43f35e9fdc23429847d57d2 100644 (file)
@@ -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
index 02d88b0a1a327202e5c6332a1013d8c1e9bb9f43..039dcc4ca87c1c4d0e5373f8d67497b8241fb1e1 100644 (file)
@@ -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;
index cc2793b4b22586b4d86edada0fd41c613d037ec1..28eb777f7b4ad939b0c7bd59f3b3b644585917db 100644 (file)
@@ -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);
 }
 
index a2fd17ad19d2b7977acc02779afb7eed321bcfc4..4aed4223e1205ee04f9b61ec18aee4ec060f55e0 100644 (file)
@@ -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 (_("<stdin>"));
+      *real_file_name_p = xstrdup (_("<stdin>"));
       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;
 }
index 5fd358f1feda211436a484df3f0f245f296de2d2..8ce0f8784b01c71b17e6d8757432d7974799de03 100644 (file)
@@ -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 */
index c9f8fa6886b4d25f4f3a5e98d17a9d143391a0c1..7437c11d8b7037455f34b0ee7b670677f42600c8 100644 (file)
@@ -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);
 }
 
 
index da2f5f2c8093ee343d0af1b246425919e8ae70eb..d2d2b7418d5ab25c836e4adbccce256f5a807b11 100644 (file)
@@ -21,6 +21,7 @@
 #define _PO_LEX_H
 
 #include <sys/types.h>
+#include <stdio.h>
 #include <stdbool.h>
 #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));
 
index 90ac988a09e6bf5ef1df6b6a4861c3446dee6a6a..4d5c45b0d281c8a48f4568294e1d901dd42028f4 100644 (file)
--- 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;
 {
index 6b4cd67c7eb074fae21ce7dc593ca0d1aa59ad1f..45c2dc631a3d67f525cb21b39eb5922474125e60 100644 (file)
--- 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.  */
index c736f617d41a164421a91a27670e3ca9ed525eeb..f0c9ba51420ffd79d840ce094da626b0fba70839 100644 (file)
@@ -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;
index 395ebee679a3ba20f44aea7d55cc9ebcb3c0f000..07d1be639c9754a8d41578be38fd98ed120639e1 100644 (file)
--- 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 <millerp@canb.auug.org.au>
diff --git a/src/x-po.c b/src/x-po.c
new file mode 100644 (file)
index 0000000..474c984
--- /dev/null
@@ -0,0 +1,311 @@
+/* xgettext PO backend.
+   Copyright (C) 1995-1998, 2000, 2001 Free Software Foundation, Inc.
+
+   This file was written by Peter Miller <millerp@canb.auug.org.au>
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2, or (at your option)
+   any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software Foundation,
+   Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include <string.h>
+
+#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 (file)
index 0000000..f02b610
--- /dev/null
@@ -0,0 +1,30 @@
+/* xgettext PO backend.
+   Copyright (C) 2001 Free Software Foundation, Inc.
+   Written by Bruno Haible <haible@clisp.cons.org>, 2001.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2, or (at your option)
+   any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software Foundation,
+   Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
+
+
+#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));
index 4d90f7d4cef4587ba6c5f9622b1267f83b2ff2c3..415951be6ebd1e9720419f4203227bef9c54bc9c 100644 (file)
@@ -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 ... */
   };
 
index 5437d7d1c11eef7b3c57eace285b4e5001c25fc6..80e9cc460411bbac68e6635cee6f4979ecb7c0a9 100644 (file)
 #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));