• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* Writing Desktop Entry files.
2    Copyright (C) 1995-1998, 2000-2003, 2005-2006, 2008-2009, 2014-2016, 2019-2020 Free Software Foundation, Inc.
3    This file was written by Daiki Ueno <ueno@gnu.org>.
4 
5    This program is free software: you can redistribute it and/or modify
6    it under the terms of the GNU General Public License as published by
7    the Free Software Foundation; either version 3 of the License, or
8    (at your option) any later version.
9 
10    This program is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13    GNU General Public License for more details.
14 
15    You should have received a copy of the GNU General Public License
16    along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
17 
18 #ifdef HAVE_CONFIG_H
19 # include <config.h>
20 #endif
21 
22 /* Specification.  */
23 #include "write-desktop.h"
24 
25 #include <assert.h>
26 #include <errno.h>
27 #include <stdint.h>
28 #include <stdlib.h>
29 #include <stdio.h>
30 #include "error.h"
31 #include "msgl-iconv.h"
32 #include "msgl-header.h"
33 #include "po-charset.h"
34 #include "read-catalog.h"
35 #include "read-po.h"
36 #include "read-desktop.h"
37 #include "fwriteerror.h"
38 #include "xalloc.h"
39 #include "gettext.h"
40 
41 #define _(str) gettext (str)
42 
43 typedef struct msgfmt_desktop_reader_ty msgfmt_desktop_reader_ty;
44 struct msgfmt_desktop_reader_ty
45 {
46   DESKTOP_READER_TY
47   msgfmt_operand_list_ty *operands;
48   hash_table *keywords;
49   FILE *output_file;
50 };
51 
52 static void
msgfmt_desktop_handle_group(struct desktop_reader_ty * reader,const char * group)53 msgfmt_desktop_handle_group (struct desktop_reader_ty *reader,
54                              const char *group)
55 {
56   msgfmt_desktop_reader_ty *msgfmt_reader = (msgfmt_desktop_reader_ty *) reader;
57 
58   fprintf (msgfmt_reader->output_file, "[%s]\n", group);
59 }
60 
61 static void
msgfmt_desktop_handle_pair(desktop_reader_ty * reader,lex_pos_ty * key_pos,const char * key,const char * locale,const char * value)62 msgfmt_desktop_handle_pair (desktop_reader_ty *reader,
63                             lex_pos_ty *key_pos,
64                             const char *key,
65                             const char *locale,
66                             const char *value)
67 {
68   msgfmt_desktop_reader_ty *msgfmt_reader = (msgfmt_desktop_reader_ty *) reader;
69   void *keyword_value;
70 
71   if (!locale)
72     {
73       /* Write translated pair, if any.  */
74       if (hash_find_entry (msgfmt_reader->keywords, key, strlen (key),
75                            &keyword_value) == 0)
76         {
77           bool is_list = (bool) (uintptr_t) keyword_value;
78           char *unescaped = desktop_unescape_string (value, is_list);
79           size_t i;
80 
81           for (i = 0; i < msgfmt_reader->operands->nitems; i++)
82             {
83               msgfmt_operand_ty *operand = &msgfmt_reader->operands->items[i];
84               message_ty *mp;
85 
86               mp = message_list_search (operand->mlp, NULL, unescaped);
87               if (mp && *mp->msgstr != '\0')
88                 {
89                   char *escaped;
90 
91                   escaped = desktop_escape_string (mp->msgstr, is_list);
92                   fprintf (msgfmt_reader->output_file,
93                            "%s[%s]=%s\n",
94                            key, operand->language, escaped);
95                   free (escaped);
96                 }
97             }
98           free (unescaped);
99         }
100 
101       /* Write untranslated pair.  */
102       fprintf (msgfmt_reader->output_file, "%s=%s\n", key, value);
103     }
104   else
105     /* Preserve already translated pair.  */
106     fprintf (msgfmt_reader->output_file, "%s[%s]=%s\n", key, locale, value);
107 }
108 
109 static void
msgfmt_desktop_handle_comment(struct desktop_reader_ty * reader,const char * s)110 msgfmt_desktop_handle_comment (struct desktop_reader_ty *reader, const char *s)
111 {
112   msgfmt_desktop_reader_ty *msgfmt_reader = (msgfmt_desktop_reader_ty *) reader;
113 
114   fputc ('#', msgfmt_reader->output_file);
115   fputs (s, msgfmt_reader->output_file);
116   fputc ('\n', msgfmt_reader->output_file);
117 }
118 
119 static void
msgfmt_desktop_handle_blank(struct desktop_reader_ty * reader,const char * s)120 msgfmt_desktop_handle_blank (struct desktop_reader_ty *reader, const char *s)
121 {
122   msgfmt_desktop_reader_ty *msgfmt_reader = (msgfmt_desktop_reader_ty *) reader;
123 
124   fputs (s, msgfmt_reader->output_file);
125   fputc ('\n', msgfmt_reader->output_file);
126 }
127 
128 desktop_reader_class_ty msgfmt_methods =
129   {
130     sizeof (msgfmt_desktop_reader_ty),
131     NULL,
132     NULL,
133     msgfmt_desktop_handle_group,
134     msgfmt_desktop_handle_pair,
135     msgfmt_desktop_handle_comment,
136     msgfmt_desktop_handle_blank
137   };
138 
139 int
msgdomain_write_desktop_bulk(msgfmt_operand_list_ty * operands,const char * template_file_name,hash_table * keywords,const char * file_name)140 msgdomain_write_desktop_bulk (msgfmt_operand_list_ty *operands,
141                               const char *template_file_name,
142                               hash_table *keywords,
143                               const char *file_name)
144 {
145   desktop_reader_ty *reader;
146   msgfmt_desktop_reader_ty *msgfmt_reader;
147   FILE *template_file;
148 
149   reader = desktop_reader_alloc (&msgfmt_methods);
150   msgfmt_reader = (msgfmt_desktop_reader_ty *) reader;
151 
152   msgfmt_reader->operands = operands;
153   msgfmt_reader->keywords = keywords;
154 
155   if (strcmp (file_name, "-") == 0)
156     msgfmt_reader->output_file = stdout;
157   else
158     {
159       msgfmt_reader->output_file = fopen (file_name, "w");
160       if (msgfmt_reader->output_file == NULL)
161         {
162           desktop_reader_free (reader);
163           error (0, errno, _("error while opening \"%s\" for writing"),
164                  file_name);
165           return 1;
166         }
167     }
168 
169   template_file = fopen (template_file_name, "r");
170   if (template_file == NULL)
171     {
172       desktop_reader_free (reader);
173       error (0, errno, _("error while opening \"%s\" for reading"),
174              template_file_name);
175       return 1;
176     }
177 
178   desktop_parse (reader, template_file, template_file_name, template_file_name);
179 
180   /* Make sure nothing went wrong.  */
181   if (fwriteerror (msgfmt_reader->output_file))
182     {
183       error (0, errno, _("error while writing \"%s\" file"),
184              file_name);
185       return 1;
186     }
187 
188   desktop_reader_free (reader);
189 
190   return 0;
191 }
192 
193 int
msgdomain_write_desktop(message_list_ty * mlp,const char * canon_encoding,const char * locale_name,const char * template_file_name,hash_table * keywords,const char * file_name)194 msgdomain_write_desktop (message_list_ty *mlp,
195                          const char *canon_encoding,
196                          const char *locale_name,
197                          const char *template_file_name,
198                          hash_table *keywords,
199                          const char *file_name)
200 {
201   msgfmt_operand_ty operand;
202   msgfmt_operand_list_ty operands;
203 
204   /* Convert the messages to Unicode.  */
205   iconv_message_list (mlp, canon_encoding, po_charset_utf8, NULL);
206 
207   /* Support for "reproducible builds": Delete information that may vary
208      between builds in the same conditions.  */
209   message_list_delete_header_field (mlp, "POT-Creation-Date:");
210 
211   /* Create a single-element operands and run the bulk operation on it.  */
212   operand.language = (char *) locale_name;
213   operand.mlp = mlp;
214   operands.nitems = 1;
215   operands.items = &operand;
216 
217   return msgdomain_write_desktop_bulk (&operands,
218                                        template_file_name,
219                                        keywords,
220                                        file_name);
221 }
222