bug-gettext
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[bug-gettext] [PATCHv3 1/2] xgettext: Add support for Desktop Entry file


From: Daiki Ueno
Subject: [bug-gettext] [PATCHv3 1/2] xgettext: Add support for Desktop Entry files
Date: Fri, 4 Apr 2014 12:51:26 +0900

---
 gettext-tools/doc/xgettext.texi        |   8 +-
 gettext-tools/src/Makefile.am          |   7 +-
 gettext-tools/src/read-desktop.c       | 528 +++++++++++++++++++++++++++++++++
 gettext-tools/src/read-desktop.h       | 121 ++++++++
 gettext-tools/src/x-desktop.c          | 177 +++++++++++
 gettext-tools/src/x-desktop.h          |  47 +++
 gettext-tools/src/xgettext.c           |   8 +-
 gettext-tools/tests/Makefile.am        |   1 +
 gettext-tools/tests/xgettext-desktop-1 |  56 ++++
 9 files changed, 947 insertions(+), 6 deletions(-)
 create mode 100644 gettext-tools/src/read-desktop.c
 create mode 100644 gettext-tools/src/read-desktop.h
 create mode 100644 gettext-tools/src/x-desktop.c
 create mode 100644 gettext-tools/src/x-desktop.h
 create mode 100755 gettext-tools/tests/xgettext-desktop-1

diff --git a/gettext-tools/doc/xgettext.texi b/gettext-tools/doc/xgettext.texi
index c8adc27..d187d63 100644
--- a/gettext-tools/doc/xgettext.texi
+++ b/gettext-tools/doc/xgettext.texi
@@ -74,7 +74,7 @@ are @code{C}, @code{C++}, @code{ObjectiveC}, @code{PO}, 
@code{Shell},
 @code{Smalltalk}, @code{Java}, @code{JavaProperties}, @code{C#}, @code{awk},
 @code{YCP}, @code{Tcl}, @code{Perl}, @code{PHP}, @code{GCC-source},
 @code{NXStringTable}, @code{RST}, @code{Glade}, @code{Lua}, @code{JavaScript},
address@hidden, @code{GSettings}.
address@hidden, @code{GSettings}, @code{Desktop}.
 
 @item -C
 @itemx --c++
@@ -181,7 +181,7 @@ escaped.
 
 This option has an effect with most languages, namely C, C++, ObjectiveC,
 Shell, Python, Lisp, EmacsLisp, librep, Java, C#, awk, Tcl, Perl, PHP,
-GCC-source, Glade, Lua, JavaScript, Vala, GSettings.
+GCC-source, Glade, Lua, JavaScript, Vala, GSettings, Desktop.
 
 The default keyword specifications, which are always looked for if not
 explicitly disabled, are language dependent.  They are:
@@ -261,6 +261,10 @@ For JavaScript: @code{_}, @code{gettext}, 
@code{dgettext:2},
 For Vala: @code{_}, @code{Q_}, @code{N_}, @code{NC_}, @code{dgettext:2},
 @code{dcgettext:2}, @code{ngettext:1,2}, @code{dngettext:2,3},
 @code{dpgettext:2c,3}, @code{dpgettext2:2c,3}.
+
address@hidden
+For Desktop: @code{Name}, @code{GenericName}, @code{Comment},
address@hidden, @code{Keywords}.
 @end itemize
 
 To disable the default keyword specifications, the option @samp{-k} or
diff --git a/gettext-tools/src/Makefile.am b/gettext-tools/src/Makefile.am
index e6713af..d43afdc 100644
--- a/gettext-tools/src/Makefile.am
+++ b/gettext-tools/src/Makefile.am
@@ -48,6 +48,7 @@ read-csharp.h write-csharp.h \
 read-resources.h write-resources.h \
 read-tcl.h write-tcl.h \
 write-qt.h \
+read-desktop.h \
 po-time.h plural-table.h lang-table.h format.h filters.h \
 xgettext.h x-c.h x-po.h x-sh.h x-python.h x-lisp.h x-elisp.h x-librep.h \
 x-scheme.h x-smalltalk.h x-java.h x-properties.h x-csharp.h x-awk.h x-ycp.h \
@@ -148,7 +149,8 @@ color.c write-catalog.c write-properties.c 
write-stringtable.c write-po.c \
 msgl-ascii.c msgl-iconv.c msgl-equal.c msgl-cat.c msgl-header.c msgl-english.c 
\
 msgl-check.c file-list.c msgl-charset.c po-time.c plural-exp.c plural-eval.c \
 plural-table.c \
-$(FORMAT_SOURCE)
+$(FORMAT_SOURCE) \
+read-desktop.c
 
 # msggrep needs pattern matching.
 LIBGREP = ../libgrep/libgrep.a
@@ -178,7 +180,8 @@ xgettext_SOURCES += \
   x-c.c x-po.c x-sh.c x-python.c x-lisp.c x-elisp.c x-librep.c x-scheme.c \
   x-smalltalk.c x-java.c x-csharp.c x-awk.c x-ycp.c x-tcl.c x-perl.c x-php.c \
   x-rst.c x-glade.c x-lua.c x-javascript.c x-vala.c x-gsettings.c \
-  libexpat-compat.c
+  libexpat-compat.c \
+  x-desktop.c
 if !WOE32DLL
 msgattrib_SOURCES = msgattrib.c
 else
diff --git a/gettext-tools/src/read-desktop.c b/gettext-tools/src/read-desktop.c
new file mode 100644
index 0000000..78d7226
--- /dev/null
+++ b/gettext-tools/src/read-desktop.c
@@ -0,0 +1,528 @@
+/* Reading Desktop Entry files.
+   Copyright (C) 1995-1998, 2000-2003, 2005-2006, 2008-2009, 2014 Free 
Software Foundation, Inc.
+   This file was written by Daiki Ueno <address@hidden>.
+
+   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 3 of the License, 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, see <http://www.gnu.org/licenses/>.  */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+/* Specification.  */
+#include "read-desktop.h"
+
+#include "xalloc.h"
+
+#include <assert.h>
+#include <errno.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "error.h"
+#include "error-progname.h"
+#include "xalloc.h"
+#include "xvasprintf.h"
+#include "c-ctype.h"
+#include "po-lex.h"
+#include "po-xerror.h"
+#include "gettext.h"
+
+#define _(str) gettext (str)
+
+/* The syntax of a Desktop Entry file is defined at
+   http://standards.freedesktop.org/desktop-entry-spec/latest/index.html.  */
+
+desktop_reader_ty *
+desktop_reader_alloc (desktop_reader_class_ty *method_table)
+{
+  desktop_reader_ty *reader;
+
+  reader = (desktop_reader_ty *) xmalloc (method_table->size);
+  reader->methods = method_table;
+  if (method_table->constructor)
+    method_table->constructor (reader);
+  return reader;
+}
+
+void
+desktop_reader_free (desktop_reader_ty *reader)
+{
+  if (reader->methods->destructor)
+    reader->methods->destructor (reader);
+  free (reader);
+}
+
+void
+desktop_reader_handle_group (desktop_reader_ty *reader, const char *group)
+{
+  if (reader->methods->handle_group)
+    reader->methods->handle_group (reader, group);
+}
+
+void
+desktop_reader_handle_pair (desktop_reader_ty *reader,
+                            lex_pos_ty *key_pos,
+                            const char *key,
+                            const char *locale,
+                            const char *value)
+{
+  if (reader->methods->handle_pair)
+    reader->methods->handle_pair (reader, key_pos, key, locale, value);
+}
+
+void
+desktop_reader_handle_comment (desktop_reader_ty *reader, const char *s)
+{
+  if (reader->methods->handle_comment)
+    reader->methods->handle_comment (reader, s);
+}
+
+void
+desktop_reader_handle_text (desktop_reader_ty *reader, const char *s)
+{
+  if (reader->methods->handle_text)
+    reader->methods->handle_text (reader, s);
+}
+
+/* Real filename, used in error messages about the input file.  */
+static const char *real_file_name;
+
+/* File name and line number.  */
+extern lex_pos_ty gram_pos;
+
+/* The input file stream.  */
+static FILE *fp;
+
+
+static int
+phase1_getc ()
+{
+  int c;
+
+  c = getc (fp);
+
+  if (c == EOF)
+    {
+      if (ferror (fp))
+        {
+          const char *errno_description = strerror (errno);
+          po_xerror (PO_SEVERITY_FATAL_ERROR, NULL, NULL, 0, 0, false,
+                     xasprintf ("%s: %s",
+                                xasprintf (_("error while reading \"%s\""),
+                                           real_file_name),
+                                errno_description));
+        }
+      return EOF;
+    }
+
+  return c;
+}
+
+static inline void
+phase1_ungetc (int c)
+{
+  if (c != EOF)
+    ungetc (c, fp);
+}
+
+
+static unsigned char phase2_pushback[2];
+static int phase2_pushback_length;
+
+static int
+phase2_getc ()
+{
+  int c;
+
+  if (phase2_pushback_length)
+    c = phase2_pushback[--phase2_pushback_length];
+  else
+    {
+      c = phase1_getc ();
+
+      if (c == '\r')
+        {
+          int c2 = phase1_getc ();
+          if (c2 == '\n')
+            c = c2;
+          else
+            phase1_ungetc (c2);
+        }
+    }
+
+  if (c == '\n')
+    gram_pos.line_number++;
+
+  return c;
+}
+
+static void
+phase2_ungetc (int c)
+{
+  if (c == '\n')
+    --gram_pos.line_number;
+  if (c != EOF)
+    phase2_pushback[phase2_pushback_length++] = c;
+}
+
+static char *
+read_until_newline (void)
+{
+  char *buffer = NULL;
+  size_t bufmax = 0;
+  size_t buflen;
+
+  buflen = 0;
+  for (;;)
+    {
+      int c;
+
+      c = phase2_getc ();
+
+      if (buflen >= bufmax)
+        {
+          bufmax += 100;
+          buffer = xrealloc (buffer, bufmax);
+        }
+
+      if (c == EOF || c == '\n')
+        break;
+
+      buffer[buflen++] = c;
+    }
+  buffer[buflen] = '\0';
+  return buffer;
+}
+
+static char *
+read_group_name (void)
+{
+  char *buffer = NULL;
+  size_t bufmax = 0;
+  size_t buflen;
+
+  buflen = 0;
+  for (;;)
+    {
+      int c;
+
+      c = phase2_getc ();
+
+      if (buflen >= bufmax)
+        {
+          bufmax += 100;
+          buffer = xrealloc (buffer, bufmax);
+        }
+
+      if (c == EOF || c == '\n' || c == ']')
+        break;
+
+      buffer[buflen++] = c;
+    }
+  buffer[buflen] = '\0';
+  return buffer;
+}
+
+static char *
+read_key_name (const char **locale)
+{
+  char *buffer = NULL;
+  size_t bufmax = 0;
+  size_t buflen;
+  const char *locale_start = NULL;
+
+  buflen = 0;
+  for (;;)
+    {
+      int c;
+
+      c = phase2_getc ();
+
+      if (buflen >= bufmax)
+        {
+          bufmax += 100;
+          buffer = xrealloc (buffer, bufmax);
+        }
+
+      if (c == EOF || c == '\n')
+        break;
+
+      if (!locale_start)
+        {
+          if (c == '[')
+            {
+              buffer[buflen++] = '\0';
+              locale_start = &buffer[buflen];
+              continue;
+            }
+          else if (!c_isalnum (c) && c != '-')
+            {
+              phase2_ungetc (c);
+              break;
+            }
+        }
+      else
+        {
+          if (c == ']')
+            {
+              buffer[buflen++] = '\0';
+              break;
+            }
+          else if (!c_isascii (c))
+            {
+              phase2_ungetc (c);
+              break;
+            }
+        }
+
+      buffer[buflen++] = c;
+    }
+  buffer[buflen] = '\0';
+
+  if (locale_start)
+    *locale = locale_start;
+
+  return buffer;
+}
+
+void
+desktop_parse (desktop_reader_ty *reader, FILE *file,
+               const char *real_filename, const char *logical_filename)
+{
+  fp = file;
+  real_file_name = real_filename;
+  gram_pos.file_name = xstrdup (real_file_name);
+  gram_pos.line_number = 1;
+
+  for (;;)
+    {
+      int c;
+
+      c = phase2_getc ();
+
+      if (c == EOF)
+        break;
+
+      if (c == '[')
+        {
+          /* A group header.  */
+          char *group_name;
+
+          group_name = read_group_name ();
+
+          do
+            c = phase2_getc ();
+          while (c == ' ' || c == '\t' || c == '\r' || c == '\n' || c == '\f');
+
+          if (c == EOF)
+            break;
+
+          phase2_ungetc (c);
+
+          desktop_reader_handle_group (reader, group_name);
+          free (group_name);
+        }
+      else if (c == '#')
+        {
+          /* A comment line.  */
+          char *comment;
+
+          comment = read_until_newline ();
+          desktop_reader_handle_comment (reader, comment);
+          free (comment);
+        }
+      else if (c_isalnum (c) || c == '-')
+        {
+          /* A key/value pair.  */
+          char *key_name;
+          const char *locale;
+
+          phase2_ungetc (c);
+
+          locale = NULL;
+          key_name = read_key_name (&locale);
+          do
+            c = phase2_getc ();
+          while (c == ' ' || c == '\t' || c == '\r' || c == '\f');
+
+          if (c == EOF)
+            break;
+
+          if (c != '=')
+            {
+              po_xerror (PO_SEVERITY_FATAL_ERROR, NULL,
+                         real_filename, gram_pos.line_number, 0, false,
+                         xasprintf (_("missing '=' after \"%s\""), key_name));
+            }
+          else
+            {
+              char *value;
+
+              do
+                c = phase2_getc ();
+              while (c == ' ' || c == '\t' || c == '\r' || c == '\f');
+
+              if (c == EOF)
+                break;
+
+              phase2_ungetc (c);
+
+              value = read_until_newline ();
+              desktop_reader_handle_pair (reader, &gram_pos,
+                                          key_name, locale, value);
+              free (value);
+            }
+          free (key_name);
+        }
+      else
+        {
+          char *text;
+
+          phase2_ungetc (c);
+
+          text = read_until_newline ();
+          desktop_reader_handle_text (reader, text);
+          free (text);
+        }
+    }
+
+  fp = NULL;
+  real_file_name = NULL;
+  gram_pos.line_number = 0;
+}
+
+char *
+desktop_escape_string (const char *s, bool is_list)
+{
+  char *buffer, *p;
+
+  p = buffer = XNMALLOC (strlen (s) * 2 + 1, char);
+
+  /* The first character must not be a whitespace.  */
+  if (*s == ' ')
+    {
+      p = stpcpy (p, "\\s");
+      s++;
+    }
+  else if (*s == '\t')
+    {
+      p = stpcpy (p, "\\t");
+      s++;
+    }
+
+  for (;; s++)
+    {
+      if (*s == '\0')
+        {
+          *p = '\0';
+          break;
+        }
+
+      switch (*s)
+        {
+        case '\n':
+          p = stpcpy (p, "\\n");
+          break;
+        case '\r':
+          p = stpcpy (p, "\\r");
+          break;
+        case '\\':
+          if (is_list && *(s + 1) == ';')
+            {
+              p = stpcpy (p, "\\;");
+              s++;
+            }
+          else
+            p = stpcpy (p, "\\\\");
+          break;
+        default:
+          *p++ = *s;
+          break;
+        }
+    }
+
+  return buffer;
+}
+
+char *
+desktop_unescape_string (const char *s, bool is_list)
+{
+  char *buffer, *p;
+
+  p = buffer = XNMALLOC (strlen (s) + 1, char);
+  for (;; s++)
+    {
+      if (*s == '\0')
+        {
+          *p = '\0';
+          break;
+        }
+
+      if (*s == '\\')
+        {
+          s++;
+
+          if (*s == '\0')
+            {
+              *p = '\0';
+              break;
+            }
+
+          switch (*s)
+            {
+            case 's':
+              *p++ = ' ';
+              break;
+            case 'n':
+              *p++ = '\n';
+              break;
+            case 't':
+              *p++ = '\t';
+              break;
+            case 'r':
+              *p++ = '\r';
+              break;
+            case ';':
+              p = stpcpy (p, "\\;");
+              break;
+            default:
+              *p++ = *s;
+              break;
+            }
+        }
+      else
+        *p++ = *s;
+    }
+  return buffer;
+}
+
+void
+desktop_add_keyword (hash_table *keywords, const char *name, bool is_list)
+{
+  hash_insert_entry (keywords, name, strlen (name), (void *) is_list);
+}
+
+void
+desktop_add_default_keywords (hash_table *keywords)
+{
+  /* When adding new keywords here, also update the documentation in
+     xgettext.texi!  */
+  desktop_add_keyword (keywords, "Name", false);
+  desktop_add_keyword (keywords, "GenericName", false);
+  desktop_add_keyword (keywords, "Comment", false);
+  desktop_add_keyword (keywords, "Icon", false);
+  desktop_add_keyword (keywords, "Keywords", true);
+}
diff --git a/gettext-tools/src/read-desktop.h b/gettext-tools/src/read-desktop.h
new file mode 100644
index 0000000..c36cc6b
--- /dev/null
+++ b/gettext-tools/src/read-desktop.h
@@ -0,0 +1,121 @@
+/* Reading Desktop Entry files.
+   Copyright (C) 1995-1998, 2000-2003, 2005-2006, 2008-2009, 2014 Free 
Software Foundation, Inc.
+   This file was written by Daiki Ueno <address@hidden>.
+
+   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 3 of the License, 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, see <http://www.gnu.org/licenses/>.  */
+
+#ifndef _READ_DESKTOP_H
+#define _READ_DESKTOP_H
+
+#include <sys/types.h>
+#include <stdio.h>
+#include "hash.h"
+#include "po-lex.h"
+#include "str-list.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Forward declaration.  */
+struct desktop_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 desktop_reader_class_ty desktop_reader_class_ty;
+struct desktop_reader_class_ty
+{
+  /* 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 desktop_reader_ty *pop);
+
+  /* what to do immediately before the instance is free()ed */
+  void (*destructor) (struct desktop_reader_ty *pop);
+
+  /* what to do with a group header */
+  void (*handle_group) (struct desktop_reader_ty *pop,
+                        const char *group);
+
+  /* what to do with a key/value pair */
+  void (*handle_pair) (struct desktop_reader_ty *pop,
+                       lex_pos_ty *key_pos,
+                       const char *key,
+                       const char *locale,
+                       const char *value);
+
+  /* what to do with a comment */
+  void (*handle_comment) (struct desktop_reader_ty *pop, const char *s);
+
+  /* what to do with other lines */
+  void (*handle_text) (struct desktop_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 in C++).
+
+   When declaring derived classes, use the DESKTOP_READER_TY define
+   at the start of the structure, to declare inherited instance variables,
+   etc.  */
+
+#define DESKTOP_READER_TY              \
+  desktop_reader_class_ty *methods;
+
+typedef struct desktop_reader_ty desktop_reader_ty;
+struct desktop_reader_ty
+{
+  DESKTOP_READER_TY
+};
+
+desktop_reader_ty *desktop_reader_alloc (desktop_reader_class_ty *methods);
+void desktop_reader_free (desktop_reader_ty *reader);
+
+void desktop_reader_handle_group (desktop_reader_ty *reader,
+                                  const char *group);
+
+void desktop_reader_handle_pair (desktop_reader_ty *reader,
+                                 lex_pos_ty *key_pos,
+                                 const char *key,
+                                 const char *locale,
+                                 const char *value);
+
+void desktop_reader_handle_comment (desktop_reader_ty *reader,
+                                    const char *s);
+
+void desktop_reader_handle_text (desktop_reader_ty *reader,
+                                 const char *s);
+
+
+void desktop_parse (desktop_reader_ty *reader, FILE *file,
+                    const char *real_filename, const char *logical_filename);
+
+
+char *desktop_escape_string (const char *s, bool is_list);
+char *desktop_unescape_string (const char *s, bool is_list);
+
+void desktop_add_keyword (hash_table *keywords, const char *name, bool 
is_list);
+void desktop_add_default_keywords (hash_table *keywords);
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif /* _READ_DESKTOP_H */
diff --git a/gettext-tools/src/x-desktop.c b/gettext-tools/src/x-desktop.c
new file mode 100644
index 0000000..8484004
--- /dev/null
+++ b/gettext-tools/src/x-desktop.c
@@ -0,0 +1,177 @@
+/* xgettext Desktop Entry backend.
+   Copyright (C) 2014 Free Software Foundation, Inc.
+
+   This file was written by Daiki Ueno <address@hidden>, 2014.
+
+   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 3 of the License, 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, see <http://www.gnu.org/licenses/>.  */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+/* Specification.  */
+#include "x-desktop.h"
+
+#include <errno.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "message.h"
+#include "xgettext.h"
+#include "error.h"
+#include "error-progname.h"
+#include "xalloc.h"
+#include "xvasprintf.h"
+#include "hash.h"
+#include "gettext.h"
+#include "read-desktop.h"
+#include "po-charset.h"
+
+#define _(s) gettext(s)
+
+#define SIZEOF(a) (sizeof(a) / sizeof(a[0]))
+
+/* ====================== Keyword set customization.  ====================== */
+
+/* The syntax of a Desktop Entry file is defined at
+   http://standards.freedesktop.org/desktop-entry-spec/latest/index.html
+
+   Basically, values with 'localestring' type can be translated.
+
+   The type of a value is determined by looking at the key associated
+   with it.  The list of available keys are listed on:
+   http://standards.freedesktop.org/desktop-entry-spec/latest/ar01s05.html  */
+
+static hash_table keywords;
+static bool default_keywords = true;
+
+static void
+add_keyword (const char *name, hash_table *keywords, bool is_list)
+{
+  if (name == NULL)
+    default_keywords = false;
+  else
+    {
+      if (keywords->table == NULL)
+        hash_init (keywords, 100);
+
+      desktop_add_keyword (keywords, name, is_list);
+    }
+}
+
+void
+x_desktop_keyword (const char *name)
+{
+  add_keyword (name, &keywords, false);
+}
+
+static void
+init_keywords (void)
+{
+  if (default_keywords)
+    {
+      if (keywords.table == NULL)
+        hash_init (&keywords, 100);
+
+      desktop_add_default_keywords (&keywords);
+      default_keywords = false;
+    }
+}
+
+typedef struct extract_desktop_reader_ty extract_desktop_reader_ty;
+struct extract_desktop_reader_ty
+{
+  DESKTOP_READER_TY
+
+  message_list_ty *mlp;
+};
+
+static void
+extract_desktop_handle_group (struct desktop_reader_ty *reader,
+                              const char *group)
+{
+  savable_comment_reset ();
+}
+
+static void
+extract_desktop_handle_pair (struct desktop_reader_ty *reader,
+                             lex_pos_ty *key_pos,
+                             const char *key,
+                             const char *locale,
+                             const char *value)
+{
+  extract_desktop_reader_ty *extract_reader =
+    (extract_desktop_reader_ty *) reader;
+  void *keyword_value;
+
+  if (!locale                   /* Skip already translated entry.  */
+      && hash_find_entry (&keywords, key, strlen (key), &keyword_value) == 0)
+    {
+      bool is_list = (bool) keyword_value;
+
+      remember_a_message (extract_reader->mlp, NULL,
+                          desktop_unescape_string (value, is_list),
+                          null_context, key_pos,
+                          NULL, savable_comment);
+    }
+  savable_comment_reset ();
+}
+
+static void
+extract_desktop_handle_comment (struct desktop_reader_ty *reader,
+                                const char *s)
+{
+  savable_comment_add (s);
+}
+
+static void
+extract_desktop_handle_text (struct desktop_reader_ty *reader,
+                             const char *s)
+{
+  savable_comment_reset ();
+}
+
+desktop_reader_class_ty extract_methods =
+  {
+    sizeof (extract_desktop_reader_ty),
+    NULL,
+    NULL,
+    extract_desktop_handle_group,
+    extract_desktop_handle_pair,
+    extract_desktop_handle_comment,
+    extract_desktop_handle_text
+  };
+
+void
+extract_desktop (FILE *f,
+                 const char *real_filename, const char *logical_filename,
+                 flag_context_list_table_ty *flag_table,
+                 msgdomain_list_ty *mdlp)
+{
+  desktop_reader_ty *reader = desktop_reader_alloc (&extract_methods);
+  extract_desktop_reader_ty *extract_reader =
+    (extract_desktop_reader_ty *) reader;
+
+  init_keywords ();
+  xgettext_current_source_encoding = po_charset_utf8;
+
+  extract_reader->mlp = mdlp->item[0]->messages;
+
+  desktop_parse (reader, f, real_filename, logical_filename);
+  desktop_reader_free (reader);
+
+  reader = NULL;
+}
diff --git a/gettext-tools/src/x-desktop.h b/gettext-tools/src/x-desktop.h
new file mode 100644
index 0000000..d9f1ff4
--- /dev/null
+++ b/gettext-tools/src/x-desktop.h
@@ -0,0 +1,47 @@
+/* xgettext Desktop Entry backend.
+   Copyright (C) 2014 Free Software Foundation, Inc.
+   Written by Daiki Ueno <address@hidden>, 2014.
+
+   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 3 of the License, 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, see <http://www.gnu.org/licenses/>.  */
+
+
+#include <stdio.h>
+
+#include "message.h"
+#include "xgettext.h"
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+#define EXTENSIONS_DESKTOP \
+  { "desktop", "Desktop" }, \
+
+#define SCANNERS_DESKTOP \
+  { "Desktop", extract_desktop, NULL, NULL, NULL }, \
+
+/* Scan a Desktop Entry file and add its translatable strings to mdlp.  */
+extern void extract_desktop (FILE *fp, const char *real_filename,
+                             const char *logical_filename,
+                             flag_context_list_table_ty *flag_table,
+                             msgdomain_list_ty *mdlp);
+
+extern void x_desktop_keyword (const char *keyword);
+
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/gettext-tools/src/xgettext.c b/gettext-tools/src/xgettext.c
index 8f14b93..0598cfa 100644
--- a/gettext-tools/src/xgettext.c
+++ b/gettext-tools/src/xgettext.c
@@ -96,6 +96,7 @@
 #include "x-javascript.h"
 #include "x-vala.h"
 #include "x-gsettings.h"
+#include "x-desktop.h"
 
 
 /* If nonzero add all comments immediately preceding one of the keywords. */
@@ -448,6 +449,7 @@ main (int argc, char *argv[])
         x_lua_keyword (optarg);
         x_javascript_keyword (optarg);
         x_vala_keyword (optarg);
+        x_desktop_keyword (optarg);
         if (optarg == NULL)
           no_default_keywords = true;
         else
@@ -886,7 +888,7 @@ Choice of input file language:\n"));
                                 EmacsLisp, librep, Scheme, Smalltalk, Java,\n\
                                 JavaProperties, C#, awk, YCP, Tcl, Perl, 
PHP,\n\
                                 GCC-source, NXStringTable, RST, Glade, Lua,\n\
-                                JavaScript, Vala)\n"));
+                                JavaScript, Vala, Desktop)\n"));
       printf (_("\
   -C, --c++                   shorthand for --language=C++\n"));
       printf (_("\
@@ -928,7 +930,7 @@ Language specific options:\n"));
                                 (only languages C, C++, ObjectiveC, Shell,\n\
                                 Python, Lisp, EmacsLisp, librep, Scheme, 
Java,\n\
                                 C#, awk, Tcl, Perl, PHP, GCC-source, Glade,\n\
-                                Lua, JavaScript, Vala)\n"));
+                                Lua, JavaScript, Vala, Desktop)\n"));
       printf (_("\
       --flag=WORD:ARG:FLAG    additional flag for strings inside the 
argument\n\
                               number ARG of keyword WORD\n"));
@@ -3257,6 +3259,7 @@ language_to_extractor (const char *name)
     SCANNERS_JAVASCRIPT
     SCANNERS_VALA
     SCANNERS_GSETTINGS
+    SCANNERS_DESKTOP
     /* Here may follow more languages and their scanners: pike, etc...
        Make sure new scanners honor the --exclude-file option.  */
   };
@@ -3344,6 +3347,7 @@ extension_to_language (const char *extension)
     EXTENSIONS_JAVASCRIPT
     EXTENSIONS_VALA
     EXTENSIONS_GSETTINGS
+    EXTENSIONS_DESKTOP
     /* Here may follow more file extensions... */
   };
 
diff --git a/gettext-tools/tests/Makefile.am b/gettext-tools/tests/Makefile.am
index 8978ca0..6d71a23 100644
--- a/gettext-tools/tests/Makefile.am
+++ b/gettext-tools/tests/Makefile.am
@@ -105,6 +105,7 @@ TESTS = gettext-1 gettext-2 gettext-3 gettext-4 gettext-5 
gettext-6 gettext-7 \
        xgettext-javascript-4 xgettext-javascript-5 xgettext-javascript-6 \
        xgettext-vala-1 \
        xgettext-gsettings-1 \
+       xgettext-desktop-1 \
        format-awk-1 format-awk-2 \
        format-boost-1 format-boost-2 \
        format-c-1 format-c-2 format-c-3 format-c-4 format-c-5 \
diff --git a/gettext-tools/tests/xgettext-desktop-1 
b/gettext-tools/tests/xgettext-desktop-1
new file mode 100755
index 0000000..0839ee5
--- /dev/null
+++ b/gettext-tools/tests/xgettext-desktop-1
@@ -0,0 +1,56 @@
+#!/bin/sh
+. "${srcdir=.}/init.sh"; path_prepend_ . ../src
+
+# Test of Desktop Entry support.
+
+cat <<EOF > xg.desktop
+[Desktop Entry]
+Type=Application
+Name =Foo
+Comment= \sThis is a \nmultiline\t comment; for testing
+Comment[foo]=Already translated comment
+Keywords=Keyword1;Keyword2;Key\;word3;
+EOF
+
+: ${XGETTEXT=xgettext}
+${XGETTEXT} --add-comments -o - xg.desktop | grep -v 'POT-Creation-Date' > 
xg-desktop.pot || exit 1
+
+cat <<\EOF > xg-desktop.ok
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <address@hidden>, YEAR.
+#
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <address@hidden>\n"
+"Language-Team: LANGUAGE <address@hidden>\n"
+"Language: \n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=CHARSET\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#: xg.desktop:4
+msgid "Foo"
+msgstr ""
+
+#: xg.desktop:5
+msgid ""
+" This is a \n"
+"multiline\t comment; for testing"
+msgstr ""
+
+#: xg.desktop:7
+msgid "Keyword1;Keyword2;Key\\;word3;"
+msgstr ""
+EOF
+
+: ${DIFF=diff}
+${DIFF} xg-desktop.ok xg-desktop.pot
+result=$?
+
+exit $result
-- 
1.8.4.2




reply via email to

[Prev in Thread] Current Thread [Next in Thread]