bug-gettext
[Top][All Lists]
Advanced

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

[bug-gettext] [PATCH 1/2] xgettext: Add support for Desktop Entry files


From: Daiki Ueno
Subject: [bug-gettext] [PATCH 1/2] xgettext: Add support for Desktop Entry files
Date: Fri, 14 Mar 2014 17:42:15 +0900

---
 gettext-tools/src/Makefile.am    |   6 +-
 gettext-tools/src/read-desktop.c | 371 +++++++++++++++++++++++++++++++++++++++
 gettext-tools/src/read-desktop.h | 111 ++++++++++++
 gettext-tools/src/x-desktop.c    | 126 +++++++++++++
 gettext-tools/src/x-desktop.h    |  47 +++++
 gettext-tools/src/xgettext.c     |   4 +
 6 files changed, 663 insertions(+), 2 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

diff --git a/gettext-tools/src/Makefile.am b/gettext-tools/src/Makefile.am
index e6713af..e69c00c 100644
--- a/gettext-tools/src/Makefile.am
+++ b/gettext-tools/src/Makefile.am
@@ -148,7 +148,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 +179,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..037555a
--- /dev/null
+++ b/gettext-tools/src/read-desktop.c
@@ -0,0 +1,371 @@
+/* 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.
+   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  */
+
+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);
+  hash_init (&reader->keywords, 100);
+  return reader;
+}
+
+void
+desktop_reader_free (desktop_reader_ty *reader)
+{
+  if (reader->methods->destructor)
+    reader->methods->destructor (reader);
+  hash_destroy (&reader->keywords);
+  free (reader);
+}
+
+void
+desktop_reader_add_keyword (desktop_reader_ty *reader,
+                                        const char *key)
+{
+  hash_insert_entry (&reader->keywords, key, strlen (key), NULL);
+}
+
+void
+desktop_reader_add_default_keywords (desktop_reader_ty *reader)
+{
+  desktop_reader_add_keyword (reader, "Name");
+  desktop_reader_add_keyword (reader, "GenericName");
+  desktop_reader_add_keyword (reader, "Comment");
+  desktop_reader_add_keyword (reader, "Icon");
+  desktop_reader_add_keyword (reader, "Keywords");
+}
+
+void
+desktop_reader_handle_localestring (desktop_reader_ty *reader,
+                                    lex_pos_ty *key_pos,
+                                    const char *key,
+                                    const char *locale,
+                                    const char *value)
+{
+  if (reader->methods->handle_localestring)
+    reader->methods->handle_localestring (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_line (desktop_reader_ty *reader, const char *s)
+{
+  if (reader->methods->handle_line)
+    reader->methods->handle_line (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 const char *
+read_until_newline (void)
+{
+  static char *buffer;
+  static size_t bufmax;
+  static 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 const char *
+read_key_name (const char **locale)
+{
+  static char *buffer;
+  static size_t bufmax;
+  static size_t buflen;
+  const char *name_end = NULL;
+  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 comment line.  */
+          desktop_reader_handle_comment (reader, read_until_newline ());
+        }
+      else if (c_isalnum (c) || c == '-')
+        {
+          const char *key;
+          const char *locale;
+          void *keyword_value;
+
+          phase2_ungetc (c);
+
+          locale = NULL;
+          key = read_key_name (&locale);
+          if (hash_find_entry (&reader->keywords, key, strlen (key),
+                               &keyword_value) == 0)
+            {
+              do
+                c = phase2_getc ();
+              while (c == ' ' || c == '\t' || c == '\r' || c == '\f');
+
+              if (c != '=')
+                {
+                  po_xerror (PO_SEVERITY_FATAL_ERROR, NULL,
+                             real_filename, gram_pos.line_number, 0, false,
+                             xasprintf (_("missing '=' after \"%s\""), key));
+                }
+              else
+                {
+                  char *value;
+
+                  do
+                    c = phase2_getc ();
+                  while (c == ' ' || c == '\t' || c == '\r' || c == '\f');
+                  phase2_ungetc (c);
+
+                  desktop_reader_handle_localestring (reader, &gram_pos,
+                                                      key, locale,
+                                                      read_until_newline ());
+                  free (value);
+                }
+            }
+          else
+            {
+              const char *rest = read_until_newline ();
+              char *result;
+
+              result = XNMALLOC (strlen (key) + strlen (rest), char);
+              stpcpy (stpcpy (result, key), rest);
+              desktop_reader_handle_line (reader, result);
+            }
+        }
+      else
+        {
+          phase2_ungetc (c);
+          desktop_reader_handle_line (reader, read_until_newline ());
+        }
+    }
+
+  fp = NULL;
+  real_file_name = NULL;
+  gram_pos.line_number = 0;
+}
diff --git a/gettext-tools/src/read-desktop.h b/gettext-tools/src/read-desktop.h
new file mode 100644
index 0000000..80f94e4
--- /dev/null
+++ b/gettext-tools/src/read-desktop.h
@@ -0,0 +1,111 @@
+/* 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 "po-lex.h"
+#include "hash.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 translatable entry */
+  void (*handle_localestring) (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_line) (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;    \
+  hash_table keywords;
+
+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_add_keyword (desktop_reader_ty *reader,
+                                 const char *keyword);
+void desktop_reader_add_default_keywords (desktop_reader_ty *reader);
+
+void desktop_reader_handle_localestring (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_line (desktop_reader_ty *reader,
+                                 const char *s);
+
+
+void desktop_parse (desktop_reader_ty *reader, FILE *file,
+                    const char *real_filename, const char *logical_filename);
+
+#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..263e976
--- /dev/null
+++ b/gettext-tools/src/x-desktop.c
@@ -0,0 +1,126 @@
+/* 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.  ====================== */
+
+static hash_table keywords;
+
+
+void
+x_desktop_keyword (const char *name)
+{
+  if (!keywords.table)
+    hash_init (&keywords, 100);
+  hash_insert_entry (&keywords, name, strlen (name), NULL);
+}
+
+static void
+init_keywords (desktop_reader_ty *reader)
+{
+  void *ptr, *data;
+  const void *key;
+  size_t keylen;
+
+  desktop_reader_add_default_keywords (reader);
+
+  ptr = NULL;
+  while (hash_iterate (&keywords, &ptr, &key, &keylen, &data) == 0)
+    desktop_reader_add_keyword (reader, key);
+}
+
+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_localestring (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;
+
+  remember_a_message (extract_reader->mlp, NULL,
+                      xstrdup (value),
+                      null_context, key_pos,
+                      NULL, NULL);
+}
+
+desktop_reader_class_ty extract_methods =
+  {
+    sizeof (extract_desktop_reader_ty),
+    NULL,
+    NULL,
+    extract_desktop_handle_localestring,
+    NULL,
+    NULL
+  };
+
+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;
+  extract_reader->mlp = mdlp->item[0]->messages;
+
+  init_keywords (reader);
+  xgettext_current_source_encoding = po_charset_utf8;
+
+  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 8e89a33..9e3aabf 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
@@ -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... */
   };
 
-- 
1.8.4.2




reply via email to

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