1 /* xgettext Desktop Entry backend.
2 Copyright (C) 2014, 2018-2020 Free Software Foundation, Inc.
3
4 This file was written by Daiki Ueno <ueno@gnu.org>, 2014.
5
6 This program is free software: you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 3 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program. If not, see <https://www.gnu.org/licenses/>. */
18
19 #ifdef HAVE_CONFIG_H
20 # include "config.h"
21 #endif
22
23 /* Specification. */
24 #include "x-desktop.h"
25
26 #include <errno.h>
27 #include <stdbool.h>
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31
32 #include "message.h"
33 #include "xgettext.h"
34 #include "xg-message.h"
35 #include "error.h"
36 #include "error-progname.h"
37 #include "xalloc.h"
38 #include "xvasprintf.h"
39 #include "mem-hash-map.h"
40 #include "gettext.h"
41 #include "read-desktop.h"
42 #include "po-charset.h"
43 #include "c-ctype.h"
44
45 #define _(s) gettext(s)
46
47 #define SIZEOF(a) (sizeof(a) / sizeof(a[0]))
48
49 /* ====================== Keyword set customization. ====================== */
50
51 /* The syntax of a Desktop Entry file is defined at
52 https://standards.freedesktop.org/desktop-entry-spec/latest/index.html
53
54 Basically, values with 'localestring' type can be localized.
55 However, the values of 'Icon', while being localizable, are not supported
56 by xgettext. See the documentation for more info.
57
58 The type of a value is determined by looking at the key associated
59 with it. The list of available keys are listed on:
60 https://standards.freedesktop.org/desktop-entry-spec/latest/ar01s04.html */
61
62 static hash_table keywords;
63 static bool default_keywords = true;
64
65 static void
add_keyword(const char * name,hash_table * keywords,bool is_list)66 add_keyword (const char *name, hash_table *keywords, bool is_list)
67 {
68 if (name == NULL)
69 default_keywords = false;
70 else
71 {
72 if (keywords->table == NULL)
73 hash_init (keywords, 100);
74
75 desktop_add_keyword (keywords, name, is_list);
76 }
77 }
78
79 void
x_desktop_keyword(const char * name)80 x_desktop_keyword (const char *name)
81 {
82 add_keyword (name, &keywords, false);
83 }
84
85 static void
init_keywords(void)86 init_keywords (void)
87 {
88 if (default_keywords)
89 {
90 if (keywords.table == NULL)
91 hash_init (&keywords, 100);
92
93 desktop_add_default_keywords (&keywords);
94 default_keywords = false;
95 }
96 }
97
98 typedef struct extract_desktop_reader_ty extract_desktop_reader_ty;
99 struct extract_desktop_reader_ty
100 {
101 DESKTOP_READER_TY
102
103 message_list_ty *mlp;
104 };
105
106 static void
extract_desktop_handle_group(struct desktop_reader_ty * reader,const char * group)107 extract_desktop_handle_group (struct desktop_reader_ty *reader,
108 const char *group)
109 {
110 savable_comment_reset ();
111 }
112
113 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)114 extract_desktop_handle_pair (struct desktop_reader_ty *reader,
115 lex_pos_ty *key_pos,
116 const char *key,
117 const char *locale,
118 const char *value)
119 {
120 extract_desktop_reader_ty *extract_reader =
121 (extract_desktop_reader_ty *) reader;
122 void *keyword_value;
123
124 if (!locale /* Skip already translated entry. */
125 && hash_find_entry (&keywords, key, strlen (key), &keyword_value) == 0)
126 {
127 bool is_list = (bool) keyword_value;
128
129 remember_a_message (extract_reader->mlp, NULL,
130 desktop_unescape_string (value, is_list), false,
131 false, null_context, key_pos,
132 NULL, savable_comment, false);
133 }
134 savable_comment_reset ();
135 }
136
137 static void
extract_desktop_handle_comment(struct desktop_reader_ty * reader,const char * buffer)138 extract_desktop_handle_comment (struct desktop_reader_ty *reader,
139 const char *buffer)
140 {
141 size_t buflen = strlen (buffer);
142 size_t bufpos = 0;
143
144 while (bufpos < buflen
145 && c_isspace (buffer[bufpos]))
146 ++bufpos;
147 while (buflen >= bufpos
148 && c_isspace (buffer[buflen - 1]))
149 --buflen;
150 if (bufpos < buflen)
151 {
152 char *comment = xstrdup (buffer);
153 comment[buflen] = 0;
154 savable_comment_add (&comment[bufpos]);
155 free (comment);
156 }
157 }
158
159 static void
extract_desktop_handle_blank(struct desktop_reader_ty * reader,const char * s)160 extract_desktop_handle_blank (struct desktop_reader_ty *reader,
161 const char *s)
162 {
163 savable_comment_reset ();
164 }
165
166 desktop_reader_class_ty extract_methods =
167 {
168 sizeof (extract_desktop_reader_ty),
169 NULL,
170 NULL,
171 extract_desktop_handle_group,
172 extract_desktop_handle_pair,
173 extract_desktop_handle_comment,
174 extract_desktop_handle_blank
175 };
176
177 void
extract_desktop(FILE * f,const char * real_filename,const char * logical_filename,flag_context_list_table_ty * flag_table,msgdomain_list_ty * mdlp)178 extract_desktop (FILE *f,
179 const char *real_filename, const char *logical_filename,
180 flag_context_list_table_ty *flag_table,
181 msgdomain_list_ty *mdlp)
182 {
183 desktop_reader_ty *reader = desktop_reader_alloc (&extract_methods);
184 extract_desktop_reader_ty *extract_reader =
185 (extract_desktop_reader_ty *) reader;
186
187 init_keywords ();
188 xgettext_current_source_encoding = po_charset_utf8;
189
190 extract_reader->mlp = mdlp->item[0]->messages;
191
192 desktop_parse (reader, f, real_filename, logical_filename);
193 desktop_reader_free (reader);
194
195 reader = NULL;
196 }
197