[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