• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /netgear-WNDR4500v2-V1.0.0.60_1.0.38/ap/gpl/timemachine/gettext-0.17/gettext-tools/src/
1/* xgettext glade backend.
2   Copyright (C) 2002-2003, 2005-2007 Free Software Foundation, Inc.
3
4   This file was written by Bruno Haible <haible@clisp.cons.org>, 2002.
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 <http://www.gnu.org/licenses/>.  */
18
19#ifdef HAVE_CONFIG_H
20# include "config.h"
21#endif
22
23/* Specification.  */
24#include "x-glade.h"
25
26#include <errno.h>
27#include <stdbool.h>
28#include <stdint.h>
29#include <stdio.h>
30#include <stdlib.h>
31#include <string.h>
32#if DYNLOAD_LIBEXPAT
33# include <dlfcn.h>
34#else
35# if HAVE_LIBEXPAT
36#  include <expat.h>
37# endif
38#endif
39
40#include "message.h"
41#include "xgettext.h"
42#include "x-glade.h"
43#include "error.h"
44#include "xerror.h"
45#include "xvasprintf.h"
46#include "basename.h"
47#include "progname.h"
48#include "xalloc.h"
49#include "hash.h"
50#include "po-charset.h"
51#include "gettext.h"
52
53#define _(s) gettext(s)
54
55
56/* glade is an XML based format.  Some example files are contained in
57   libglade-0.16.  */
58
59
60/* ====================== Keyword set customization.  ====================== */
61
62/* If true extract all strings.  */
63static bool extract_all = false;
64
65static hash_table keywords;
66static bool default_keywords = true;
67
68
69void
70x_glade_extract_all ()
71{
72  extract_all = true;
73}
74
75
76void
77x_glade_keyword (const char *name)
78{
79  if (name == NULL)
80    default_keywords = false;
81  else
82    {
83      if (keywords.table == NULL)
84	hash_init (&keywords, 100);
85
86      hash_insert_entry (&keywords, name, strlen (name), NULL);
87    }
88}
89
90/* Finish initializing the keywords hash table.
91   Called after argument processing, before each file is processed.  */
92static void
93init_keywords ()
94{
95  if (default_keywords)
96    {
97      /* When adding new keywords here, also update the documentation in
98	 xgettext.texi!  */
99      x_glade_keyword ("label");
100      x_glade_keyword ("title");
101      x_glade_keyword ("text");
102      x_glade_keyword ("format");
103      x_glade_keyword ("copyright");
104      x_glade_keyword ("comments");
105      x_glade_keyword ("preview_text");
106      x_glade_keyword ("tooltip");
107      default_keywords = false;
108    }
109}
110
111
112/* ======================= Different libexpat ABIs.  ======================= */
113
114/* There are three different ABIs of libexpat, regarding the functions
115   XML_GetCurrentLineNumber and XML_GetCurrentColumnNumber.
116   In expat < 2.0, they return an 'int'.
117   In expat >= 2.0, they return
118     - a 'long' if expat was compiled with the default flags, or
119     - a 'long long' if expat was compiled with -DXML_LARGE_SIZE.
120   But the <expat.h> include file does not contain the information whether
121   expat was compiled with -DXML_LARGE_SIZE; so the include file is lying!
122   For this information, we need to call XML_GetFeatureList(), for
123   expat >= 2.0.1; for expat = 2.0.0, we have to assume the default flags.  */
124
125#if !DYNLOAD_LIBEXPAT
126
127# if XML_MAJOR_VERSION >= 2
128
129/* expat >= 2.0 -> Return type is 'int64_t' worst-case.  */
130
131/* Put the function pointers into variables, because some GCC 4 versions
132   generate an abort when we convert symbol address to different function
133   pointer types.  */
134static void *p_XML_GetCurrentLineNumber = (void *) &XML_GetCurrentLineNumber;
135static void *p_XML_GetCurrentColumnNumber = (void *) &XML_GetCurrentColumnNumber;
136
137/* Return true if libexpat was compiled with -DXML_LARGE_SIZE.  */
138static bool
139is_XML_LARGE_SIZE_ABI (void)
140{
141  static bool tested;
142  static bool is_large;
143
144  if (!tested)
145    {
146      const XML_Feature *features;
147
148      is_large = false;
149      for (features = XML_GetFeatureList (); features->name != NULL; features++)
150	if (strcmp (features->name, "XML_LARGE_SIZE") == 0)
151	  {
152	    is_large = true;
153	    break;
154	  }
155
156      tested = true;
157    }
158  return is_large;
159}
160
161static int64_t
162GetCurrentLineNumber (XML_Parser parser)
163{
164  if (is_XML_LARGE_SIZE_ABI ())
165    return ((int64_t (*) (XML_Parser)) p_XML_GetCurrentLineNumber) (parser);
166  else
167    return ((long (*) (XML_Parser)) p_XML_GetCurrentLineNumber) (parser);
168}
169#  define XML_GetCurrentLineNumber GetCurrentLineNumber
170
171static int64_t
172GetCurrentColumnNumber (XML_Parser parser)
173{
174  if (is_XML_LARGE_SIZE_ABI ())
175    return ((int64_t (*) (XML_Parser)) p_XML_GetCurrentColumnNumber) (parser);
176  else
177    return ((long (*) (XML_Parser)) p_XML_GetCurrentColumnNumber) (parser);
178}
179#  define XML_GetCurrentColumnNumber GetCurrentColumnNumber
180
181# else
182
183/* expat < 2.0 -> Return type is 'int'.  */
184
185# endif
186
187#endif
188
189
190/* ===================== Dynamic loading of libexpat.  ===================== */
191
192#if DYNLOAD_LIBEXPAT
193
194typedef struct
195  {
196    int major;
197    int minor;
198    int micro;
199  }
200  XML_Expat_Version;
201enum XML_FeatureEnum { XML_FEATURE_END = 0 };
202typedef struct
203  {
204    enum XML_FeatureEnum feature;
205    const char *name;
206    long int value;
207  }
208  XML_Feature;
209typedef void *XML_Parser;
210typedef char XML_Char;
211typedef char XML_LChar;
212enum XML_Error { XML_ERROR_NONE };
213typedef void (*XML_StartElementHandler) (void *userData, const XML_Char *name, const XML_Char **atts);
214typedef void (*XML_EndElementHandler) (void *userData, const XML_Char *name);
215typedef void (*XML_CharacterDataHandler) (void *userData, const XML_Char *s, int len);
216typedef void (*XML_CommentHandler) (void *userData, const XML_Char *data);
217
218static XML_Expat_Version (*p_XML_ExpatVersionInfo) (void);
219static const XML_Feature * (*p_XML_GetFeatureList) (void);
220static XML_Parser (*p_XML_ParserCreate) (const XML_Char *encoding);
221static void (*p_XML_SetElementHandler) (XML_Parser parser, XML_StartElementHandler start, XML_EndElementHandler end);
222static void (*p_XML_SetCharacterDataHandler) (XML_Parser parser, XML_CharacterDataHandler handler);
223static void (*p_XML_SetCommentHandler) (XML_Parser parser, XML_CommentHandler handler);
224static int (*p_XML_Parse) (XML_Parser parser, const char *s, int len, int isFinal);
225static enum XML_Error (*p_XML_GetErrorCode) (XML_Parser parser);
226static void *p_XML_GetCurrentLineNumber;
227static void *p_XML_GetCurrentColumnNumber;
228static void (*p_XML_ParserFree) (XML_Parser parser);
229static const XML_LChar * (*p_XML_ErrorString) (int code);
230
231#define XML_ExpatVersionInfo (*p_XML_ExpatVersionInfo)
232#define XML_GetFeatureList (*p_XML_GetFeatureList)
233
234enum XML_Size_ABI { is_int, is_long, is_int64_t };
235
236static enum XML_Size_ABI
237get_XML_Size_ABI (void)
238{
239  static bool tested;
240  static enum XML_Size_ABI abi;
241
242  if (!tested)
243    {
244      if (XML_ExpatVersionInfo () .major >= 2)
245	/* expat >= 2.0 -> XML_Size is 'int64_t' or 'long'.  */
246	{
247	  const XML_Feature *features;
248
249	  abi = is_long;
250	  for (features = XML_GetFeatureList ();
251	       features->name != NULL;
252	       features++)
253	    if (strcmp (features->name, "XML_LARGE_SIZE") == 0)
254	      {
255		abi = is_int64_t;
256		break;
257	      }
258	}
259      else
260	/* expat < 2.0 -> XML_Size is 'int'.  */
261	abi = is_int;
262      tested = true;
263    }
264  return abi;
265}
266
267#define XML_ParserCreate (*p_XML_ParserCreate)
268#define XML_SetElementHandler (*p_XML_SetElementHandler)
269#define XML_SetCharacterDataHandler (*p_XML_SetCharacterDataHandler)
270#define XML_SetCommentHandler (*p_XML_SetCommentHandler)
271#define XML_Parse (*p_XML_Parse)
272#define XML_GetErrorCode (*p_XML_GetErrorCode)
273
274static int64_t
275XML_GetCurrentLineNumber (XML_Parser parser)
276{
277  switch (get_XML_Size_ABI ())
278    {
279    case is_int:
280      return ((int (*) (XML_Parser)) p_XML_GetCurrentLineNumber) (parser);
281    case is_long:
282      return ((long (*) (XML_Parser)) p_XML_GetCurrentLineNumber) (parser);
283    case is_int64_t:
284      return ((int64_t (*) (XML_Parser)) p_XML_GetCurrentLineNumber) (parser);
285    default:
286      abort ();
287    }
288}
289
290static int64_t
291XML_GetCurrentColumnNumber (XML_Parser parser)
292{
293  switch (get_XML_Size_ABI ())
294    {
295    case is_int:
296      return ((int (*) (XML_Parser)) p_XML_GetCurrentColumnNumber) (parser);
297    case is_long:
298      return ((long (*) (XML_Parser)) p_XML_GetCurrentColumnNumber) (parser);
299    case is_int64_t:
300      return ((int64_t (*) (XML_Parser)) p_XML_GetCurrentColumnNumber) (parser);
301    default:
302      abort ();
303    }
304}
305
306#define XML_ParserFree (*p_XML_ParserFree)
307#define XML_ErrorString (*p_XML_ErrorString)
308
309static int libexpat_loaded = 0;
310
311static bool
312load_libexpat ()
313{
314  if (libexpat_loaded == 0)
315    {
316      void *handle;
317
318      /* Try to load libexpat-2.x.  */
319      handle = dlopen ("libexpat.so.1", RTLD_LAZY);
320      if (handle == NULL)
321	/* Try to load libexpat-1.x.  */
322	handle = dlopen ("libexpat.so.0", RTLD_LAZY);
323      if (handle != NULL
324	  && (p_XML_ExpatVersionInfo =
325		(XML_Expat_Version (*) (void))
326		dlsym (handle, "XML_ExpatVersionInfo")) != NULL
327	  && (p_XML_GetFeatureList =
328		(const XML_Feature * (*) (void))
329		dlsym (handle, "XML_GetFeatureList")) != NULL
330	  && (p_XML_ParserCreate =
331		(XML_Parser (*) (const XML_Char *))
332		dlsym (handle, "XML_ParserCreate")) != NULL
333	  && (p_XML_SetElementHandler =
334		(void (*) (XML_Parser, XML_StartElementHandler, XML_EndElementHandler))
335		dlsym (handle, "XML_SetElementHandler")) != NULL
336	  && (p_XML_SetCharacterDataHandler =
337		(void (*) (XML_Parser, XML_CharacterDataHandler))
338		dlsym (handle, "XML_SetCharacterDataHandler")) != NULL
339	  && (p_XML_SetCommentHandler =
340		(void (*) (XML_Parser, XML_CommentHandler))
341		dlsym (handle, "XML_SetCommentHandler")) != NULL
342	  && (p_XML_Parse =
343		(int (*) (XML_Parser, const char *, int, int))
344		dlsym (handle, "XML_Parse")) != NULL
345	  && (p_XML_GetErrorCode =
346		(enum XML_Error (*) (XML_Parser))
347		dlsym (handle, "XML_GetErrorCode")) != NULL
348	  && (p_XML_GetCurrentLineNumber =
349		dlsym (handle, "XML_GetCurrentLineNumber")) != NULL
350	  && (p_XML_GetCurrentColumnNumber =
351		dlsym (handle, "XML_GetCurrentColumnNumber")) != NULL
352	  && (p_XML_ParserFree =
353		(void (*) (XML_Parser))
354		dlsym (handle, "XML_ParserFree")) != NULL
355	  && (p_XML_ErrorString =
356		(const XML_LChar * (*) (int))
357		dlsym (handle, "XML_ErrorString")) != NULL)
358	libexpat_loaded = 1;
359      else
360	libexpat_loaded = -1;
361    }
362  return libexpat_loaded >= 0;
363}
364
365#define LIBEXPAT_AVAILABLE() (load_libexpat ())
366
367#elif HAVE_LIBEXPAT
368
369#define LIBEXPAT_AVAILABLE() true
370
371#endif
372
373/* ============================= XML parsing.  ============================= */
374
375#if DYNLOAD_LIBEXPAT || HAVE_LIBEXPAT
376
377/* Accumulator for the extracted messages.  */
378static message_list_ty *mlp;
379
380/* Logical filename, used to label the extracted messages.  */
381static char *logical_file_name;
382
383/* XML parser.  */
384static XML_Parser parser;
385
386struct element_state
387{
388  bool extract_string;
389  int lineno;
390  char *buffer;
391  size_t bufmax;
392  size_t buflen;
393};
394static struct element_state *stack;
395static size_t stack_size;
396
397/* Ensures stack_size >= size.  */
398static void
399ensure_stack_size (size_t size)
400{
401  if (size > stack_size)
402    {
403      stack_size = 2 * stack_size;
404      if (stack_size < size)
405	stack_size = size;
406      stack =
407	(struct element_state *)
408	xrealloc (stack, stack_size * sizeof (struct element_state));
409    }
410}
411
412static size_t stack_depth;
413
414/* Callback called when <element> is seen.  */
415static void
416start_element_handler (void *userData, const char *name,
417		       const char **attributes)
418{
419  struct element_state *p;
420  void *hash_result;
421
422  /* Increase stack depth.  */
423  stack_depth++;
424  ensure_stack_size (stack_depth + 1);
425
426  /* Don't extract a string for the containing element.  */
427  stack[stack_depth - 1].extract_string = false;
428
429  p = &stack[stack_depth];
430  p->extract_string = extract_all;
431  /* In Glade 1, a few specific elements are translatable.  */
432  if (!p->extract_string)
433    p->extract_string =
434      (hash_find_entry (&keywords, name, strlen (name), &hash_result) == 0);
435  /* In Glade 2, all <property> and <atkproperty> elements are translatable
436     that have the attribute translatable="yes".  */
437  if (!p->extract_string
438      && (strcmp (name, "property") == 0 || strcmp (name, "atkproperty") == 0))
439    {
440      bool has_translatable = false;
441      const char **attp = attributes;
442      while (*attp != NULL)
443	{
444	  if (strcmp (attp[0], "translatable") == 0)
445	    {
446	      has_translatable = (strcmp (attp[1], "yes") == 0);
447	      break;
448	    }
449	  attp += 2;
450	}
451      p->extract_string = has_translatable;
452    }
453  if (!p->extract_string
454      && strcmp (name, "atkaction") == 0)
455    {
456      const char **attp = attributes;
457      while (*attp != NULL)
458	{
459	  if (strcmp (attp[0], "description") == 0)
460	    {
461	      if (strcmp (attp[1], "") != 0)
462		{
463		  lex_pos_ty pos;
464
465		  pos.file_name = logical_file_name;
466		  pos.line_number = XML_GetCurrentLineNumber (parser);
467
468		  remember_a_message (mlp, NULL, xstrdup (attp[1]),
469				      null_context, &pos, savable_comment);
470		}
471	      break;
472	    }
473	  attp += 2;
474	}
475    }
476  p->lineno = XML_GetCurrentLineNumber (parser);
477  p->buffer = NULL;
478  p->bufmax = 0;
479  p->buflen = 0;
480  if (!p->extract_string)
481    savable_comment_reset ();
482}
483
484/* Callback called when </element> is seen.  */
485static void
486end_element_handler (void *userData, const char *name)
487{
488  struct element_state *p = &stack[stack_depth];
489
490  /* Actually extract string.  */
491  if (p->extract_string)
492    {
493      /* Don't extract the empty string.  */
494      if (p->buflen > 0)
495	{
496	  lex_pos_ty pos;
497
498	  if (p->buflen == p->bufmax)
499	    p->buffer = (char *) xrealloc (p->buffer, p->buflen + 1);
500	  p->buffer[p->buflen] = '\0';
501
502	  pos.file_name = logical_file_name;
503	  pos.line_number = p->lineno;
504
505	  remember_a_message (mlp, NULL, p->buffer, null_context, &pos,
506			      savable_comment);
507	  p->buffer = NULL;
508	}
509    }
510
511  /* Free memory for this stack level.  */
512  if (p->buffer != NULL)
513    free (p->buffer);
514
515  /* Decrease stack depth.  */
516  stack_depth--;
517
518  savable_comment_reset ();
519}
520
521/* Callback called when some text is seen.  */
522static void
523character_data_handler (void *userData, const char *s, int len)
524{
525  struct element_state *p = &stack[stack_depth];
526
527  /* Accumulate character data.  */
528  if (len > 0)
529    {
530      if (p->buflen + len > p->bufmax)
531	{
532	  p->bufmax = 2 * p->bufmax;
533	  if (p->bufmax < p->buflen + len)
534	    p->bufmax = p->buflen + len;
535	  p->buffer = (char *) xrealloc (p->buffer, p->bufmax);
536	}
537      memcpy (p->buffer + p->buflen, s, len);
538      p->buflen += len;
539    }
540}
541
542/* Callback called when some comment text is seen.  */
543static void
544comment_handler (void *userData, const char *data)
545{
546  /* Split multiline comment into lines, and remove leading and trailing
547     whitespace.  */
548  char *copy = xstrdup (data);
549  char *p = copy;
550  char *q;
551
552  for (p = copy; (q = strchr (p, '\n')) != NULL; p = q + 1)
553    {
554      while (p[0] == ' ' || p[0] == '\t')
555	p++;
556      while (q > p && (q[-1] == ' ' || q[-1] == '\t'))
557	q--;
558      *q = '\0';
559      savable_comment_add (p);
560    }
561  q = p + strlen (p);
562  while (p[0] == ' ' || p[0] == '\t')
563    p++;
564  while (q > p && (q[-1] == ' ' || q[-1] == '\t'))
565    q--;
566  *q = '\0';
567  savable_comment_add (p);
568  free (copy);
569}
570
571
572static void
573do_extract_glade (FILE *fp,
574		  const char *real_filename, const char *logical_filename,
575		  msgdomain_list_ty *mdlp)
576{
577  mlp = mdlp->item[0]->messages;
578
579  /* expat feeds us strings in UTF-8 encoding.  */
580  xgettext_current_source_encoding = po_charset_utf8;
581
582  logical_file_name = xstrdup (logical_filename);
583
584  init_keywords ();
585
586  parser = XML_ParserCreate (NULL);
587  if (parser == NULL)
588    error (EXIT_FAILURE, 0, _("memory exhausted"));
589
590  XML_SetElementHandler (parser, start_element_handler, end_element_handler);
591  XML_SetCharacterDataHandler (parser, character_data_handler);
592  XML_SetCommentHandler (parser, comment_handler);
593
594  stack_depth = 0;
595
596  while (!feof (fp))
597    {
598      char buf[4096];
599      int count = fread (buf, 1, sizeof buf, fp);
600
601      if (count == 0)
602	{
603	  if (ferror (fp))
604	    error (EXIT_FAILURE, errno, _("\
605error while reading \"%s\""), real_filename);
606	  /* EOF reached.  */
607	  break;
608	}
609
610      if (XML_Parse (parser, buf, count, 0) == 0)
611	error (EXIT_FAILURE, 0, _("%s:%lu:%lu: %s"), logical_filename,
612	       (unsigned long) XML_GetCurrentLineNumber (parser),
613	       (unsigned long) XML_GetCurrentColumnNumber (parser) + 1,
614	       XML_ErrorString (XML_GetErrorCode (parser)));
615    }
616
617  if (XML_Parse (parser, NULL, 0, 1) == 0)
618    error (EXIT_FAILURE, 0, _("%s:%lu:%lu: %s"), logical_filename,
619	   (unsigned long) XML_GetCurrentLineNumber (parser),
620	   (unsigned long) XML_GetCurrentColumnNumber (parser) + 1,
621	   XML_ErrorString (XML_GetErrorCode (parser)));
622
623  XML_ParserFree (parser);
624
625  /* Close scanner.  */
626  logical_file_name = NULL;
627  parser = NULL;
628}
629
630#endif
631
632void
633extract_glade (FILE *fp,
634	       const char *real_filename, const char *logical_filename,
635	       flag_context_list_table_ty *flag_table,
636	       msgdomain_list_ty *mdlp)
637{
638#if DYNLOAD_LIBEXPAT || HAVE_LIBEXPAT
639  if (LIBEXPAT_AVAILABLE ())
640    do_extract_glade (fp, real_filename, logical_filename, mdlp);
641  else
642#endif
643    {
644      multiline_error (xstrdup (""),
645		       xasprintf (_("\
646Language \"glade\" is not supported. %s relies on expat.\n\
647This version was built without expat.\n"),
648				  basename (program_name)));
649      exit (EXIT_FAILURE);
650    }
651}
652