1 /* Reading PO files, abstract class.
2 Copyright (C) 1995-1996, 1998, 2000-2005 Free Software Foundation, Inc.
4 This file was written by Peter Miller <millerp@canb.auug.org.au>
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)
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. */
26 #include "read-po-abstract.h"
32 #include "read-properties.h"
33 #include "read-stringtable.h"
37 /* Local variables. */
38 static abstract_po_reader_ty
*callback_arg
;
41 /* ========================================================================= */
42 /* Allocating and freeing instances of abstract_po_reader_ty. */
45 abstract_po_reader_ty
*
46 po_reader_alloc (abstract_po_reader_class_ty
*method_table
)
48 abstract_po_reader_ty
*pop
;
50 pop
= (abstract_po_reader_ty
*) xmalloc (method_table
->size
);
51 pop
->methods
= method_table
;
52 if (method_table
->constructor
)
53 method_table
->constructor (pop
);
59 po_reader_free (abstract_po_reader_ty
*pop
)
61 if (pop
->methods
->destructor
)
62 pop
->methods
->destructor (pop
);
67 /* ========================================================================= */
68 /* Inline functions to invoke the methods. */
72 call_parse_brief (abstract_po_reader_ty
*pop
)
74 if (pop
->methods
->parse_brief
)
75 pop
->methods
->parse_brief (pop
);
79 call_parse_debrief (abstract_po_reader_ty
*pop
)
81 if (pop
->methods
->parse_debrief
)
82 pop
->methods
->parse_debrief (pop
);
86 call_directive_domain (abstract_po_reader_ty
*pop
, char *name
)
88 if (pop
->methods
->directive_domain
)
89 pop
->methods
->directive_domain (pop
, name
);
93 call_directive_message (abstract_po_reader_ty
*pop
,
95 lex_pos_ty
*msgid_pos
,
97 char *msgstr
, size_t msgstr_len
,
98 lex_pos_ty
*msgstr_pos
,
99 bool force_fuzzy
, bool obsolete
)
101 if (pop
->methods
->directive_message
)
102 pop
->methods
->directive_message (pop
, msgid
, msgid_pos
, msgid_plural
,
103 msgstr
, msgstr_len
, msgstr_pos
,
104 force_fuzzy
, obsolete
);
108 call_comment (abstract_po_reader_ty
*pop
, const char *s
)
110 if (pop
->methods
->comment
!= NULL
)
111 pop
->methods
->comment (pop
, s
);
115 call_comment_dot (abstract_po_reader_ty
*pop
, const char *s
)
117 if (pop
->methods
->comment_dot
!= NULL
)
118 pop
->methods
->comment_dot (pop
, s
);
122 call_comment_filepos (abstract_po_reader_ty
*pop
, const char *name
, size_t line
)
124 if (pop
->methods
->comment_filepos
)
125 pop
->methods
->comment_filepos (pop
, name
, line
);
129 call_comment_special (abstract_po_reader_ty
*pop
, const char *s
)
131 if (pop
->methods
->comment_special
!= NULL
)
132 pop
->methods
->comment_special (pop
, s
);
136 /* ========================================================================= */
137 /* Exported functions. */
141 po_scan_start (abstract_po_reader_ty
*pop
)
143 /* The parse will call the po_callback_... functions (see below)
144 when the various directive are recognised. The callback_arg
145 variable is used to tell these functions which instance is to
146 have the relevant method invoked. */
149 call_parse_brief (pop
);
153 po_scan_end (abstract_po_reader_ty
*pop
)
155 call_parse_debrief (pop
);
161 po_scan (abstract_po_reader_ty
*pop
, FILE *fp
,
162 const char *real_filename
, const char *logical_filename
,
163 input_syntax_ty syntax
)
165 /* Parse the stream's content. */
169 lex_start (fp
, real_filename
, logical_filename
);
175 case syntax_properties
:
177 properties_parse (pop
, fp
, real_filename
, logical_filename
);
180 case syntax_stringtable
:
182 stringtable_parse (pop
, fp
, real_filename
, logical_filename
);
189 if (error_message_count
> 0)
190 po_error (EXIT_FAILURE
, 0,
191 ngettext ("found %d fatal error", "found %d fatal errors",
192 error_message_count
),
193 error_message_count
);
194 error_message_count
= 0;
198 /* ========================================================================= */
199 /* Callbacks used by po-gram.y or po-lex.c, indirectly from po_scan. */
202 /* This function is called by po_gram_lex() whenever a domain directive
205 po_callback_domain (char *name
)
207 /* assert(callback_arg); */
208 call_directive_domain (callback_arg
, name
);
212 /* This function is called by po_gram_lex() whenever a message has been
215 po_callback_message (char *msgid
, lex_pos_ty
*msgid_pos
, char *msgid_plural
,
216 char *msgstr
, size_t msgstr_len
, lex_pos_ty
*msgstr_pos
,
217 bool force_fuzzy
, bool obsolete
)
219 /* assert(callback_arg); */
220 call_directive_message (callback_arg
, msgid
, msgid_pos
, msgid_plural
,
221 msgstr
, msgstr_len
, msgstr_pos
,
222 force_fuzzy
, obsolete
);
227 po_callback_comment (const char *s
)
229 /* assert(callback_arg); */
230 call_comment (callback_arg
, s
);
235 po_callback_comment_dot (const char *s
)
237 /* assert(callback_arg); */
238 call_comment_dot (callback_arg
, s
);
242 /* This function is called by po_parse_comment_filepos(), once for each
245 po_callback_comment_filepos (const char *name
, size_t line
)
247 /* assert(callback_arg); */
248 call_comment_filepos (callback_arg
, name
, line
);
253 po_callback_comment_special (const char *s
)
255 /* assert(callback_arg); */
256 call_comment_special (callback_arg
, s
);
260 /* Parse a special comment and put the result in *fuzzyp, formatp, *wrapp. */
262 po_parse_comment_special (const char *s
,
263 bool *fuzzyp
, enum is_format formatp
[NFORMATS
],
269 for (i
= 0; i
< NFORMATS
; i
++)
270 formatp
[i
] = undecided
;
277 /* Skip whitespace. */
278 while (*s
!= '\0' && strchr ("\n \t\r\f\v,", *s
) != NULL
)
281 /* Collect a token. */
283 while (*s
!= '\0' && strchr ("\n \t\r\f\v,", *s
) == NULL
)
289 /* Accept fuzzy flag. */
290 if (len
== 5 && memcmp (t
, "fuzzy", 5) == 0)
296 /* Accept format description. */
297 if (len
>= 7 && memcmp (t
+ len
- 7, "-format", 7) == 0)
301 enum is_format value
;
306 if (n
>= 3 && memcmp (p
, "no-", 3) == 0)
312 else if (n
>= 9 && memcmp (p
, "possible-", 9) == 0)
318 else if (n
>= 11 && memcmp (p
, "impossible-", 11) == 0)
327 for (i
= 0; i
< NFORMATS
; i
++)
328 if (strlen (format_language
[i
]) == n
329 && memcmp (format_language
[i
], p
, n
) == 0)
338 /* Accept wrap description. */
339 if (len
== 4 && memcmp (t
, "wrap", 4) == 0)
344 if (len
== 7 && memcmp (t
, "no-wrap", 7) == 0)
350 /* Unknown special comment marker. It may have been generated
351 from a future xgettext version. Ignore it. */
357 /* Parse a GNU style file comment.
358 Syntax: an arbitrary number of
362 The latter style, without line number, occurs in PO files converted e.g.
363 from Pascal .rst files or from OpenOffice resource files.
364 Call po_callback_comment_filepos for each of them. */
366 po_parse_comment_filepos (const char *s
)
370 while (*s
== ' ' || *s
== '\t' || *s
== '\n')
374 const char *string_start
= s
;
378 while (!(*s
== '\0' || *s
== ' ' || *s
== '\t' || *s
== '\n'));
380 /* See if there is a COLON and NUMBER after the STRING, separated
381 through optional spaces. */
385 while (*p
== ' ' || *p
== '\t' || *p
== '\n')
392 while (*p
== ' ' || *p
== '\t' || *p
== '\n')
395 if (*p
>= '0' && *p
<= '9')
397 /* Accumulate a number. */
402 n
= n
* 10 + (*p
- '0');
405 while (*p
>= '0' && *p
<= '9');
407 if (*p
== '\0' || *p
== ' ' || *p
== '\t' || *p
== '\n')
409 /* Parsed a GNU style file comment with spaces. */
410 const char *string_end
= s
;
411 size_t string_length
= string_end
- string_start
;
412 char *string
= (char *) xmalloc (string_length
+ 1);
414 memcpy (string
, string_start
, string_length
);
415 string
[string_length
] = '\0';
417 po_callback_comment_filepos (string
, n
);
428 /* See if there is a COLON at the end of STRING and a NUMBER after
429 it, separated through optional spaces. */
434 while (*p
== ' ' || *p
== '\t' || *p
== '\n')
437 if (*p
>= '0' && *p
<= '9')
439 /* Accumulate a number. */
444 n
= n
* 10 + (*p
- '0');
447 while (*p
>= '0' && *p
<= '9');
449 if (*p
== '\0' || *p
== ' ' || *p
== '\t' || *p
== '\n')
451 /* Parsed a GNU style file comment with spaces. */
452 const char *string_end
= s
- 1;
453 size_t string_length
= string_end
- string_start
;
454 char *string
= (char *) xmalloc (string_length
+ 1);
456 memcpy (string
, string_start
, string_length
);
457 string
[string_length
] = '\0';
459 po_callback_comment_filepos (string
, n
);
469 /* See if there is a COLON and NUMBER at the end of the STRING,
470 without separating spaces. */
474 while (p
> string_start
)
477 if (!(*p
>= '0' && *p
<= '9'))
484 /* p now points to the beginning of the trailing digits segment
485 at the end of STRING. */
488 && p
> string_start
+ 1
491 /* Parsed a GNU style file comment without spaces. */
492 const char *string_end
= p
- 1;
494 /* Accumulate a number. */
500 n
= n
* 10 + (*p
- '0');
506 size_t string_length
= string_end
- string_start
;
507 char *string
= (char *) xmalloc (string_length
+ 1);
509 memcpy (string
, string_start
, string_length
);
510 string
[string_length
] = '\0';
512 po_callback_comment_filepos (string
, n
);
522 /* Parsed a file comment without line number. */
524 const char *string_end
= s
;
525 size_t string_length
= string_end
- string_start
;
526 char *string
= (char *) xmalloc (string_length
+ 1);
528 memcpy (string
, string_start
, string_length
);
529 string
[string_length
] = '\0';
531 po_callback_comment_filepos (string
, (size_t)(-1));
540 /* Parse a SunOS or Solaris style file comment.
541 Syntax of SunOS style:
542 FILE_KEYWORD COLON STRING COMMA LINE_KEYWORD COLON NUMBER
543 Syntax of Solaris style:
544 FILE_KEYWORD COLON STRING COMMA LINE_KEYWORD NUMBER_KEYWORD COLON NUMBER
546 FILE_KEYWORD ::= "file" | "File"
549 LINE_KEYWORD ::= "line"
550 NUMBER_KEYWORD ::= "number"
552 Return true if parsed, false if not a comment of this form. */
554 po_parse_comment_solaris_filepos (const char *s
)
557 && (s
[1] == 'F' || s
[1] == 'f')
558 && s
[2] == 'i' && s
[3] == 'l' && s
[4] == 'e'
561 const char *string_start
;
562 const char *string_end
;
565 const char *p
= s
+ 6;
567 while (*p
== ' ' || *p
== '\t')
572 for (string_end
= string_start
; *string_end
!= '\0'; string_end
++)
574 const char *p
= string_end
;
576 while (*p
== ' ' || *p
== '\t')
583 while (*p
== ' ' || *p
== '\t')
586 if (p
[0] == 'l' && p
[1] == 'i' && p
[2] == 'n' && p
[3] == 'e')
590 while (*p
== ' ' || *p
== '\t')
593 if (p
[0] == 'n' && p
[1] == 'u' && p
[2] == 'm'
594 && p
[3] == 'b' && p
[4] == 'e' && p
[5] == 'r')
597 while (*p
== ' ' || *p
== '\t')
605 if (*p
>= '0' && *p
<= '9')
607 /* Accumulate a number. */
612 n
= n
* 10 + (*p
- '0');
615 while (*p
>= '0' && *p
<= '9');
617 while (*p
== ' ' || *p
== '\t' || *p
== '\n')
622 /* Parsed a Sun style file comment. */
623 size_t string_length
= string_end
- string_start
;
625 (char *) xmalloc (string_length
+ 1);
627 memcpy (string
, string_start
, string_length
);
628 string
[string_length
] = '\0';
630 po_callback_comment_filepos (string
, n
);
646 /* This function is called by po_gram_lex() whenever a comment is
647 seen. It analyzes the comment to see what sort it is, and then
648 dispatches it to the appropriate method: call_comment, call_comment_dot,
649 call_comment_filepos (via po_parse_comment_filepos), or
650 call_comment_special. */
652 po_callback_comment_dispatcher (const char *s
)
655 po_callback_comment_dot (s
+ 1);
658 /* Parse the file location string. The appropriate callback will be
660 po_parse_comment_filepos (s
+ 1);
662 else if (*s
== ',' || *s
== '!')
664 /* Get all entries in the special comment line. */
665 po_callback_comment_special (s
+ 1);
669 /* It looks like a plain vanilla comment, but Solaris-style file
670 position lines do, too. Try to parse the lot. If the parse
671 succeeds, the appropriate callback will be invoked. */
672 if (po_parse_comment_solaris_filepos (s
))
673 /* Do nothing, it is a Sun-style file pos line. */ ;
675 po_callback_comment (s
);