--- 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 <[email protected]>. + + 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 <[email protected]>. + + 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 <[email protected]>, 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 <[email protected]>, 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
