No empty .Rs/.Re
[netbsd-mini2440.git] / gnu / dist / gettext / gettext-tools / src / x-glade.c
blob745257480aa95774533148d63c8021867d893486
1 /* xgettext glade backend.
2 Copyright (C) 2002-2003 Free Software Foundation, Inc.
4 This file was written by Bruno Haible <haible@clisp.cons.org>, 2002.
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 2, or (at your option)
9 any later version.
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.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software Foundation,
18 Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
20 #ifdef HAVE_CONFIG_H
21 # include "config.h"
22 #endif
24 #include <errno.h>
25 #include <stdbool.h>
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #if DYNLOAD_LIBEXPAT
30 # include <dlfcn.h>
31 #else
32 # if HAVE_LIBEXPAT
33 # include <expat.h>
34 # endif
35 #endif
37 #include "message.h"
38 #include "xgettext.h"
39 #include "x-glade.h"
40 #include "error.h"
41 #include "xerror.h"
42 #include "basename.h"
43 #include "progname.h"
44 #include "xalloc.h"
45 #include "exit.h"
46 #include "hash.h"
47 #include "po-charset.h"
48 #include "gettext.h"
50 #define _(s) gettext(s)
53 /* glade is an XML based format. Some example files are contained in
54 libglade-0.16. */
57 /* ====================== Keyword set customization. ====================== */
59 /* If true extract all strings. */
60 static bool extract_all = false;
62 static hash_table keywords;
63 static bool default_keywords = true;
66 void
67 x_glade_extract_all ()
69 extract_all = true;
73 void
74 x_glade_keyword (const char *name)
76 if (name == NULL)
77 default_keywords = false;
78 else
80 if (keywords.table == NULL)
81 init_hash (&keywords, 100);
83 insert_entry (&keywords, name, strlen (name), NULL);
87 /* Finish initializing the keywords hash table.
88 Called after argument processing, before each file is processed. */
89 static void
90 init_keywords ()
92 if (default_keywords)
94 x_glade_keyword ("label");
95 x_glade_keyword ("title");
96 x_glade_keyword ("text");
97 x_glade_keyword ("format");
98 x_glade_keyword ("copyright");
99 x_glade_keyword ("comments");
100 x_glade_keyword ("preview_text");
101 x_glade_keyword ("tooltip");
102 default_keywords = false;
107 /* ===================== Dynamic loading of libexpat. ===================== */
109 #if DYNLOAD_LIBEXPAT
111 typedef void *XML_Parser;
112 typedef char XML_Char;
113 typedef char XML_LChar;
114 enum XML_Error { XML_ERROR_NONE };
115 typedef void (*XML_StartElementHandler) (void *userData, const XML_Char *name, const XML_Char **atts);
116 typedef void (*XML_EndElementHandler) (void *userData, const XML_Char *name);
117 typedef void (*XML_CharacterDataHandler) (void *userData, const XML_Char *s, int len);
118 typedef void (*XML_CommentHandler) (void *userData, const XML_Char *data);
120 static XML_Parser (*p_XML_ParserCreate) (const XML_Char *encoding);
121 static void (*p_XML_SetElementHandler) (XML_Parser parser, XML_StartElementHandler start, XML_EndElementHandler end);
122 static void (*p_XML_SetCharacterDataHandler) (XML_Parser parser, XML_CharacterDataHandler handler);
123 static void (*p_XML_SetCommentHandler) (XML_Parser parser, XML_CommentHandler handler);
124 static int (*p_XML_Parse) (XML_Parser parser, const char *s, int len, int isFinal);
125 static enum XML_Error (*p_XML_GetErrorCode) (XML_Parser parser);
126 static int (*p_XML_GetCurrentLineNumber) (XML_Parser parser);
127 static int (*p_XML_GetCurrentColumnNumber) (XML_Parser parser);
128 static void (*p_XML_ParserFree) (XML_Parser parser);
129 static const XML_LChar * (*p_XML_ErrorString) (int code);
131 #define XML_ParserCreate (*p_XML_ParserCreate)
132 #define XML_SetElementHandler (*p_XML_SetElementHandler)
133 #define XML_SetCharacterDataHandler (*p_XML_SetCharacterDataHandler)
134 #define XML_SetCommentHandler (*p_XML_SetCommentHandler)
135 #define XML_Parse (*p_XML_Parse)
136 #define XML_GetErrorCode (*p_XML_GetErrorCode)
137 #define XML_GetCurrentLineNumber (*p_XML_GetCurrentLineNumber)
138 #define XML_GetCurrentColumnNumber (*p_XML_GetCurrentColumnNumber)
139 #define XML_ParserFree (*p_XML_ParserFree)
140 #define XML_ErrorString (*p_XML_ErrorString)
142 static int libexpat_loaded = 0;
144 static bool
145 load_libexpat ()
147 if (libexpat_loaded == 0)
149 void *handle = dlopen ("libexpat.so.0", RTLD_LAZY);
150 if (handle != NULL
151 && (p_XML_ParserCreate = dlsym (handle, "XML_ParserCreate")) != NULL
152 && (p_XML_SetElementHandler = dlsym (handle, "XML_SetElementHandler")) != NULL
153 && (p_XML_SetCharacterDataHandler = dlsym (handle, "XML_SetCharacterDataHandler")) != NULL
154 && (p_XML_SetCommentHandler = dlsym (handle, "XML_SetCommentHandler")) != NULL
155 && (p_XML_Parse = dlsym (handle, "XML_Parse")) != NULL
156 && (p_XML_GetErrorCode = dlsym (handle, "XML_GetErrorCode")) != NULL
157 && (p_XML_GetCurrentLineNumber = dlsym (handle, "XML_GetCurrentLineNumber")) != NULL
158 && (p_XML_GetCurrentColumnNumber = dlsym (handle, "XML_GetCurrentColumnNumber")) != NULL
159 && (p_XML_ParserFree = dlsym (handle, "XML_ParserFree")) != NULL
160 && (p_XML_ErrorString = dlsym (handle, "XML_ErrorString")) != NULL)
161 libexpat_loaded = 1;
162 else
163 libexpat_loaded = -1;
165 return libexpat_loaded >= 0;
168 #define LIBEXPAT_AVAILABLE() (load_libexpat ())
170 #elif HAVE_LIBEXPAT
172 #define LIBEXPAT_AVAILABLE() true
174 #endif
176 /* ============================= XML parsing. ============================= */
178 #if DYNLOAD_LIBEXPAT || HAVE_LIBEXPAT
180 /* Accumulator for the extracted messages. */
181 static message_list_ty *mlp;
183 /* Logical filename, used to label the extracted messages. */
184 static char *logical_file_name;
186 /* XML parser. */
187 static XML_Parser parser;
189 struct element_state
191 bool extract_string;
192 int lineno;
193 char *buffer;
194 size_t bufmax;
195 size_t buflen;
197 static struct element_state *stack;
198 static size_t stack_size;
200 /* Ensures stack_size >= size. */
201 static void
202 ensure_stack_size (size_t size)
204 if (size > stack_size)
206 stack_size = 2 * stack_size;
207 if (stack_size < size)
208 stack_size = size;
209 stack =
210 (struct element_state *)
211 xrealloc (stack, stack_size * sizeof (struct element_state));
215 static size_t stack_depth;
217 /* Callback called when <element> is seen. */
218 static void
219 start_element_handler (void *userData, const char *name,
220 const char **attributes)
222 struct element_state *p;
223 void *hash_result;
225 /* Increase stack depth. */
226 stack_depth++;
227 ensure_stack_size (stack_depth + 1);
229 /* Don't extract a string for the containing element. */
230 stack[stack_depth - 1].extract_string = false;
232 p = &stack[stack_depth];
233 p->extract_string = extract_all;
234 /* In Glade 1, a few specific elements are translatable. */
235 if (!p->extract_string)
236 p->extract_string =
237 (find_entry (&keywords, name, strlen (name), &hash_result) == 0);
238 /* In Glade 2, all <property> and <atkproperty> elements are translatable
239 that have the attribute translatable="yes". */
240 if (!p->extract_string
241 && (strcmp (name, "property") == 0 || strcmp (name, "atkproperty") == 0))
243 bool has_translatable = false;
244 const char **attp = attributes;
245 while (*attp != NULL)
247 if (strcmp (attp[0], "translatable") == 0)
249 has_translatable = (strcmp (attp[1], "yes") == 0);
250 break;
252 attp += 2;
254 p->extract_string = has_translatable;
256 if (!p->extract_string
257 && strcmp (name, "atkaction") == 0)
259 const char **attp = attributes;
260 while (*attp != NULL)
262 if (strcmp (attp[0], "description") == 0)
264 if (strcmp (attp[1], "") != 0)
266 lex_pos_ty pos;
268 pos.file_name = logical_file_name;
269 pos.line_number = XML_GetCurrentLineNumber (parser);
271 remember_a_message (mlp, xstrdup (attp[1]),
272 null_context, &pos);
274 break;
276 attp += 2;
279 p->lineno = XML_GetCurrentLineNumber (parser);
280 p->buffer = NULL;
281 p->bufmax = 0;
282 p->buflen = 0;
283 if (!p->extract_string)
284 xgettext_comment_reset ();
287 /* Callback called when </element> is seen. */
288 static void
289 end_element_handler (void *userData, const char *name)
291 struct element_state *p = &stack[stack_depth];
293 /* Actually extract string. */
294 if (p->extract_string)
296 /* Don't extract the empty string. */
297 if (p->buflen > 0)
299 lex_pos_ty pos;
301 if (p->buflen == p->bufmax)
302 p->buffer = (char *) xrealloc (p->buffer, p->buflen + 1);
303 p->buffer[p->buflen] = '\0';
305 pos.file_name = logical_file_name;
306 pos.line_number = p->lineno;
308 remember_a_message (mlp, p->buffer, null_context, &pos);
309 p->buffer = NULL;
313 /* Free memory for this stack level. */
314 if (p->buffer != NULL)
315 free (p->buffer);
317 /* Decrease stack depth. */
318 stack_depth--;
320 xgettext_comment_reset ();
323 /* Callback called when some text is seen. */
324 static void
325 character_data_handler (void *userData, const char *s, int len)
327 struct element_state *p = &stack[stack_depth];
329 /* Accumulate character data. */
330 if (len > 0)
332 if (p->buflen + len > p->bufmax)
334 p->bufmax = 2 * p->bufmax;
335 if (p->bufmax < p->buflen + len)
336 p->bufmax = p->buflen + len;
337 p->buffer = (char *) xrealloc (p->buffer, p->bufmax);
339 memcpy (p->buffer + p->buflen, s, len);
340 p->buflen += len;
344 /* Callback called when some comment text is seen. */
345 static void
346 comment_handler (void *userData, const char *data)
348 /* Split multiline comment into lines, and remove leading and trailing
349 whitespace. */
350 char *copy = xstrdup (data);
351 char *p = copy;
352 char *q;
354 for (p = copy; (q = strchr (p, '\n')) != NULL; p = q + 1)
356 while (p[0] == ' ' || p[0] == '\t')
357 p++;
358 while (q > p && (q[-1] == ' ' || q[-1] == '\t'))
359 q--;
360 *q = '\0';
361 xgettext_comment_add (p);
363 q = p + strlen (p);
364 while (p[0] == ' ' || p[0] == '\t')
365 p++;
366 while (q > p && (q[-1] == ' ' || q[-1] == '\t'))
367 q--;
368 *q = '\0';
369 xgettext_comment_add (p);
370 free (copy);
374 static void
375 do_extract_glade (FILE *fp,
376 const char *real_filename, const char *logical_filename,
377 msgdomain_list_ty *mdlp)
379 mlp = mdlp->item[0]->messages;
381 /* expat feeds us strings in UTF-8 encoding. */
382 xgettext_current_source_encoding = po_charset_utf8;
384 logical_file_name = xstrdup (logical_filename);
386 init_keywords ();
388 parser = XML_ParserCreate (NULL);
389 if (parser == NULL)
390 error (EXIT_FAILURE, 0, _("memory exhausted"));
392 XML_SetElementHandler (parser, start_element_handler, end_element_handler);
393 XML_SetCharacterDataHandler (parser, character_data_handler);
394 XML_SetCommentHandler (parser, comment_handler);
396 stack_depth = 0;
398 while (!feof (fp))
400 char buf[4096];
401 int count = fread (buf, 1, sizeof buf, fp);
403 if (count == 0)
405 if (ferror (fp))
406 error (EXIT_FAILURE, errno, _("\
407 error while reading \"%s\""), real_filename);
408 /* EOF reached. */
409 break;
412 if (XML_Parse (parser, buf, count, 0) == 0)
413 error (EXIT_FAILURE, 0, _("%s:%d:%d: %s"), logical_filename,
414 XML_GetCurrentLineNumber (parser),
415 XML_GetCurrentColumnNumber (parser) + 1,
416 XML_ErrorString (XML_GetErrorCode (parser)));
419 if (XML_Parse (parser, NULL, 0, 1) == 0)
420 error (EXIT_FAILURE, 0, _("%s:%d:%d: %s"), logical_filename,
421 XML_GetCurrentLineNumber (parser),
422 XML_GetCurrentColumnNumber (parser) + 1,
423 XML_ErrorString (XML_GetErrorCode (parser)));
425 XML_ParserFree (parser);
427 /* Close scanner. */
428 logical_file_name = NULL;
429 parser = NULL;
432 #endif
434 void
435 extract_glade (FILE *fp,
436 const char *real_filename, const char *logical_filename,
437 flag_context_list_table_ty *flag_table,
438 msgdomain_list_ty *mdlp)
440 #if DYNLOAD_LIBEXPAT || HAVE_LIBEXPAT
441 if (LIBEXPAT_AVAILABLE ())
442 do_extract_glade (fp, real_filename, logical_filename, mdlp);
443 else
444 #endif
446 multiline_error (xstrdup (""),
447 xasprintf (_("\
448 Language \"glade\" is not supported. %s relies on expat.\n\
449 This version was built without expat.\n"),
450 basename (program_name)));
451 exit (EXIT_FAILURE);