xref: /netbsd-src/external/gpl2/gettext/dist/gettext-tools/src/x-java.c (revision 946379e7b37692fc43f68eb0d1c10daa0a7f3b6c)
1*946379e7Schristos /* xgettext Java backend.
2*946379e7Schristos    Copyright (C) 2003, 2005-2006 Free Software Foundation, Inc.
3*946379e7Schristos    Written by Bruno Haible <bruno@clisp.org>, 2003.
4*946379e7Schristos 
5*946379e7Schristos    This program is free software; you can redistribute it and/or modify
6*946379e7Schristos    it under the terms of the GNU General Public License as published by
7*946379e7Schristos    the Free Software Foundation; either version 2, or (at your option)
8*946379e7Schristos    any later version.
9*946379e7Schristos 
10*946379e7Schristos    This program is distributed in the hope that it will be useful,
11*946379e7Schristos    but WITHOUT ANY WARRANTY; without even the implied warranty of
12*946379e7Schristos    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13*946379e7Schristos    GNU General Public License for more details.
14*946379e7Schristos 
15*946379e7Schristos    You should have received a copy of the GNU General Public License
16*946379e7Schristos    along with this program; if not, write to the Free Software Foundation,
17*946379e7Schristos    Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.  */
18*946379e7Schristos 
19*946379e7Schristos #ifdef HAVE_CONFIG_H
20*946379e7Schristos # include "config.h"
21*946379e7Schristos #endif
22*946379e7Schristos 
23*946379e7Schristos #include <errno.h>
24*946379e7Schristos #include <stdbool.h>
25*946379e7Schristos #include <stdio.h>
26*946379e7Schristos #include <stdlib.h>
27*946379e7Schristos #include <string.h>
28*946379e7Schristos 
29*946379e7Schristos #include "message.h"
30*946379e7Schristos #include "xgettext.h"
31*946379e7Schristos #include "x-java.h"
32*946379e7Schristos #include "error.h"
33*946379e7Schristos #include "xalloc.h"
34*946379e7Schristos #include "exit.h"
35*946379e7Schristos #include "hash.h"
36*946379e7Schristos #include "po-charset.h"
37*946379e7Schristos #include "utf16-ucs4.h"
38*946379e7Schristos #include "ucs4-utf8.h"
39*946379e7Schristos #include "gettext.h"
40*946379e7Schristos 
41*946379e7Schristos #define _(s) gettext(s)
42*946379e7Schristos 
43*946379e7Schristos #define SIZEOF(a) (sizeof(a) / sizeof(a[0]))
44*946379e7Schristos 
45*946379e7Schristos 
46*946379e7Schristos /* The Java syntax is defined in the
47*946379e7Schristos      Java Language Specification, Second Edition,
48*946379e7Schristos      (available from http://java.sun.com/),
49*946379e7Schristos      chapter 3 "Lexical Structure".  */
50*946379e7Schristos 
51*946379e7Schristos 
52*946379e7Schristos /* ====================== Keyword set customization.  ====================== */
53*946379e7Schristos 
54*946379e7Schristos /* If true extract all strings.  */
55*946379e7Schristos static bool extract_all = false;
56*946379e7Schristos 
57*946379e7Schristos static hash_table keywords;
58*946379e7Schristos static bool default_keywords = true;
59*946379e7Schristos 
60*946379e7Schristos 
61*946379e7Schristos void
x_java_extract_all()62*946379e7Schristos x_java_extract_all ()
63*946379e7Schristos {
64*946379e7Schristos   extract_all = true;
65*946379e7Schristos }
66*946379e7Schristos 
67*946379e7Schristos 
68*946379e7Schristos void
x_java_keyword(const char * name)69*946379e7Schristos x_java_keyword (const char *name)
70*946379e7Schristos {
71*946379e7Schristos   if (name == NULL)
72*946379e7Schristos     default_keywords = false;
73*946379e7Schristos   else
74*946379e7Schristos     {
75*946379e7Schristos       const char *end;
76*946379e7Schristos       struct callshape shape;
77*946379e7Schristos       const char *colon;
78*946379e7Schristos 
79*946379e7Schristos       if (keywords.table == NULL)
80*946379e7Schristos 	hash_init (&keywords, 100);
81*946379e7Schristos 
82*946379e7Schristos       split_keywordspec (name, &end, &shape);
83*946379e7Schristos 
84*946379e7Schristos       /* The characters between name and end should form a valid Java
85*946379e7Schristos 	 identifier sequence with dots.
86*946379e7Schristos 	 A colon means an invalid parse in split_keywordspec().  */
87*946379e7Schristos       colon = strchr (name, ':');
88*946379e7Schristos       if (colon == NULL || colon >= end)
89*946379e7Schristos 	insert_keyword_callshape (&keywords, name, end - name, &shape);
90*946379e7Schristos     }
91*946379e7Schristos }
92*946379e7Schristos 
93*946379e7Schristos /* Finish initializing the keywords hash table.
94*946379e7Schristos    Called after argument processing, before each file is processed.  */
95*946379e7Schristos static void
init_keywords()96*946379e7Schristos init_keywords ()
97*946379e7Schristos {
98*946379e7Schristos   if (default_keywords)
99*946379e7Schristos     {
100*946379e7Schristos       /* When adding new keywords here, also update the documentation in
101*946379e7Schristos 	 xgettext.texi!  */
102*946379e7Schristos       x_java_keyword ("GettextResource.gettext:2");	/* static method */
103*946379e7Schristos       x_java_keyword ("GettextResource.ngettext:2,3");	/* static method */
104*946379e7Schristos       x_java_keyword ("gettext");
105*946379e7Schristos       x_java_keyword ("ngettext:1,2");
106*946379e7Schristos       x_java_keyword ("getString");	/* ResourceBundle.getString */
107*946379e7Schristos       default_keywords = false;
108*946379e7Schristos     }
109*946379e7Schristos }
110*946379e7Schristos 
111*946379e7Schristos void
init_flag_table_java()112*946379e7Schristos init_flag_table_java ()
113*946379e7Schristos {
114*946379e7Schristos   xgettext_record_flag ("GettextResource.gettext:2:pass-java-format");
115*946379e7Schristos   xgettext_record_flag ("GettextResource.ngettext:2:pass-java-format");
116*946379e7Schristos   xgettext_record_flag ("GettextResource.ngettext:3:pass-java-format");
117*946379e7Schristos   xgettext_record_flag ("gettext:1:pass-java-format");
118*946379e7Schristos   xgettext_record_flag ("ngettext:1:pass-java-format");
119*946379e7Schristos   xgettext_record_flag ("ngettext:2:pass-java-format");
120*946379e7Schristos   xgettext_record_flag ("getString:1:pass-java-format");
121*946379e7Schristos   xgettext_record_flag ("MessageFormat:1:java-format");
122*946379e7Schristos   xgettext_record_flag ("MessageFormat.format:1:java-format");
123*946379e7Schristos }
124*946379e7Schristos 
125*946379e7Schristos 
126*946379e7Schristos /* ======================== Reading of characters.  ======================== */
127*946379e7Schristos 
128*946379e7Schristos /* Real filename, used in error messages about the input file.  */
129*946379e7Schristos static const char *real_file_name;
130*946379e7Schristos 
131*946379e7Schristos /* Logical filename and line number, used to label the extracted messages.  */
132*946379e7Schristos static char *logical_file_name;
133*946379e7Schristos static int line_number;
134*946379e7Schristos 
135*946379e7Schristos /* The input file stream.  */
136*946379e7Schristos static FILE *fp;
137*946379e7Schristos 
138*946379e7Schristos 
139*946379e7Schristos /* Fetch the next single-byte character from the input file.
140*946379e7Schristos    Pushback can consist of an unlimited number of 'u' followed by up to 4
141*946379e7Schristos    other characters.  */
142*946379e7Schristos 
143*946379e7Schristos /* Special coding of multiple 'u's in the pushback buffer.  */
144*946379e7Schristos #define MULTIPLE_U(count) (0x1000 + (count))
145*946379e7Schristos 
146*946379e7Schristos static int phase1_pushback[5];
147*946379e7Schristos static unsigned int phase1_pushback_length;
148*946379e7Schristos 
149*946379e7Schristos static int
phase1_getc()150*946379e7Schristos phase1_getc ()
151*946379e7Schristos {
152*946379e7Schristos   int c;
153*946379e7Schristos 
154*946379e7Schristos   if (phase1_pushback_length)
155*946379e7Schristos     {
156*946379e7Schristos       c = phase1_pushback[--phase1_pushback_length];
157*946379e7Schristos       if (c >= MULTIPLE_U (0))
158*946379e7Schristos 	{
159*946379e7Schristos 	  if (c > MULTIPLE_U (1))
160*946379e7Schristos 	    phase1_pushback[phase1_pushback_length++] = c - 1;
161*946379e7Schristos 	  return 'u';
162*946379e7Schristos 	}
163*946379e7Schristos       else
164*946379e7Schristos 	return c;
165*946379e7Schristos     }
166*946379e7Schristos 
167*946379e7Schristos   c = getc (fp);
168*946379e7Schristos 
169*946379e7Schristos   if (c == EOF)
170*946379e7Schristos     {
171*946379e7Schristos       if (ferror (fp))
172*946379e7Schristos 	error (EXIT_FAILURE, errno, _("\
173*946379e7Schristos error while reading \"%s\""), real_file_name);
174*946379e7Schristos     }
175*946379e7Schristos 
176*946379e7Schristos   return c;
177*946379e7Schristos }
178*946379e7Schristos 
179*946379e7Schristos /* Supports any number of 'u' and up to 4 arbitrary characters of pushback.  */
180*946379e7Schristos static void
phase1_ungetc(int c)181*946379e7Schristos phase1_ungetc (int c)
182*946379e7Schristos {
183*946379e7Schristos   if (c != EOF)
184*946379e7Schristos     {
185*946379e7Schristos       if (c == 'u')
186*946379e7Schristos 	{
187*946379e7Schristos 	  if (phase1_pushback_length > 0
188*946379e7Schristos 	      && phase1_pushback[phase1_pushback_length - 1] >= MULTIPLE_U (0))
189*946379e7Schristos 	    phase1_pushback[phase1_pushback_length - 1]++;
190*946379e7Schristos 	  else
191*946379e7Schristos 	    {
192*946379e7Schristos 	      if (phase1_pushback_length == SIZEOF (phase1_pushback))
193*946379e7Schristos 		abort ();
194*946379e7Schristos 	      phase1_pushback[phase1_pushback_length++] = MULTIPLE_U (1);
195*946379e7Schristos 	    }
196*946379e7Schristos 	}
197*946379e7Schristos       else
198*946379e7Schristos 	{
199*946379e7Schristos 	  if (phase1_pushback_length == SIZEOF (phase1_pushback))
200*946379e7Schristos 	    abort ();
201*946379e7Schristos 	  phase1_pushback[phase1_pushback_length++] = c;
202*946379e7Schristos 	}
203*946379e7Schristos     }
204*946379e7Schristos }
205*946379e7Schristos 
206*946379e7Schristos 
207*946379e7Schristos /* Fetch the next single-byte character or Unicode character from the file.
208*946379e7Schristos    (Here, as in the Java Language Specification, when we say "Unicode
209*946379e7Schristos    character", we actually mean "UTF-16 encoding unit".)  */
210*946379e7Schristos 
211*946379e7Schristos /* Return value of phase 2, 3, 4 when EOF is reached.  */
212*946379e7Schristos #define P2_EOF 0xffff
213*946379e7Schristos 
214*946379e7Schristos /* Convert an UTF-16 code point to a return value that can be distinguished
215*946379e7Schristos    from a single-byte return value.  */
216*946379e7Schristos #define UNICODE(code) (0x10000 + (code))
217*946379e7Schristos 
218*946379e7Schristos /* Test a return value of phase 2, 3, 4 whether it designates an UTF-16 code
219*946379e7Schristos    point.  */
220*946379e7Schristos #define IS_UNICODE(p2_result) ((p2_result) >= 0x10000)
221*946379e7Schristos 
222*946379e7Schristos /* Extract the UTF-16 code of a return value that satisfies IS_UNICODE.  */
223*946379e7Schristos #define UTF16_VALUE(p2_result) ((p2_result) - 0x10000)
224*946379e7Schristos 
225*946379e7Schristos /* Reduces a return value of phase 2, 3, 4 by unmasking the UNICODE bit,
226*946379e7Schristos    so that it can be more easily compared against an ASCII character.
227*946379e7Schristos    (RED (c) == 'x')  is equivalent to  (c == 'x' || c == UNICODE ('x')).  */
228*946379e7Schristos #define RED(p2_result) ((p2_result) & 0xffff)
229*946379e7Schristos 
230*946379e7Schristos static int phase2_pushback[1];
231*946379e7Schristos static int phase2_pushback_length;
232*946379e7Schristos 
233*946379e7Schristos static int
phase2_getc()234*946379e7Schristos phase2_getc ()
235*946379e7Schristos {
236*946379e7Schristos   int c;
237*946379e7Schristos 
238*946379e7Schristos   if (phase2_pushback_length)
239*946379e7Schristos     return phase2_pushback[--phase2_pushback_length];
240*946379e7Schristos 
241*946379e7Schristos   c = phase1_getc ();
242*946379e7Schristos   if (c == EOF)
243*946379e7Schristos     return P2_EOF;
244*946379e7Schristos   if (c == '\\')
245*946379e7Schristos     {
246*946379e7Schristos       c = phase1_getc ();
247*946379e7Schristos       if (c == 'u')
248*946379e7Schristos 	{
249*946379e7Schristos 	  unsigned int u_count = 1;
250*946379e7Schristos 	  unsigned char buf[4];
251*946379e7Schristos 	  unsigned int n;
252*946379e7Schristos 	  int i;
253*946379e7Schristos 
254*946379e7Schristos 	  for (;;)
255*946379e7Schristos 	    {
256*946379e7Schristos 	      c = phase1_getc ();
257*946379e7Schristos 	      if (c != 'u')
258*946379e7Schristos 		break;
259*946379e7Schristos 	      u_count++;
260*946379e7Schristos 	    }
261*946379e7Schristos 	  phase1_ungetc (c);
262*946379e7Schristos 
263*946379e7Schristos 	  n = 0;
264*946379e7Schristos 	  for (i = 0; i < 4; i++)
265*946379e7Schristos 	    {
266*946379e7Schristos 	      c = phase1_getc ();
267*946379e7Schristos 
268*946379e7Schristos 	      if (c >= '0' && c <= '9')
269*946379e7Schristos 		n = (n << 4) + (c - '0');
270*946379e7Schristos 	      else if (c >= 'A' && c <= 'F')
271*946379e7Schristos 		n = (n << 4) + (c - 'A' + 10);
272*946379e7Schristos 	      else if (c >= 'a' && c <= 'f')
273*946379e7Schristos 		n = (n << 4) + (c - 'a' + 10);
274*946379e7Schristos 	      else
275*946379e7Schristos 		{
276*946379e7Schristos 		  phase1_ungetc (c);
277*946379e7Schristos 		  while (--i >= 0)
278*946379e7Schristos 		    phase1_ungetc (buf[i]);
279*946379e7Schristos 		  for (; u_count > 0; u_count--)
280*946379e7Schristos 		    phase1_ungetc ('u');
281*946379e7Schristos 		  return '\\';
282*946379e7Schristos 		}
283*946379e7Schristos 
284*946379e7Schristos 	      buf[i] = c;
285*946379e7Schristos 	    }
286*946379e7Schristos 	  return UNICODE (n);
287*946379e7Schristos 	}
288*946379e7Schristos       phase1_ungetc (c);
289*946379e7Schristos       return '\\';
290*946379e7Schristos     }
291*946379e7Schristos   return c;
292*946379e7Schristos }
293*946379e7Schristos 
294*946379e7Schristos /* Supports only one pushback character.  */
295*946379e7Schristos static void
phase2_ungetc(int c)296*946379e7Schristos phase2_ungetc (int c)
297*946379e7Schristos {
298*946379e7Schristos   if (c != P2_EOF)
299*946379e7Schristos     {
300*946379e7Schristos       if (phase2_pushback_length == SIZEOF (phase2_pushback))
301*946379e7Schristos 	abort ();
302*946379e7Schristos       phase2_pushback[phase2_pushback_length++] = c;
303*946379e7Schristos     }
304*946379e7Schristos }
305*946379e7Schristos 
306*946379e7Schristos 
307*946379e7Schristos /* Fetch the next single-byte character or Unicode character from the file.
308*946379e7Schristos    With line number handling.
309*946379e7Schristos    Convert line terminators to '\n' or UNICODE ('\n').  */
310*946379e7Schristos 
311*946379e7Schristos static int phase3_pushback[2];
312*946379e7Schristos static int phase3_pushback_length;
313*946379e7Schristos 
314*946379e7Schristos static int
phase3_getc()315*946379e7Schristos phase3_getc ()
316*946379e7Schristos {
317*946379e7Schristos   int c;
318*946379e7Schristos 
319*946379e7Schristos   if (phase3_pushback_length)
320*946379e7Schristos     {
321*946379e7Schristos       c = phase3_pushback[--phase3_pushback_length];
322*946379e7Schristos       if (c == '\n')
323*946379e7Schristos 	++line_number;
324*946379e7Schristos       return c;
325*946379e7Schristos     }
326*946379e7Schristos 
327*946379e7Schristos   c = phase2_getc ();
328*946379e7Schristos 
329*946379e7Schristos   /* Handle line terminators.  */
330*946379e7Schristos   if (RED (c) == '\r')
331*946379e7Schristos     {
332*946379e7Schristos       int c1 = phase2_getc ();
333*946379e7Schristos 
334*946379e7Schristos       if (RED (c1) != '\n')
335*946379e7Schristos 	phase2_ungetc (c1);
336*946379e7Schristos 
337*946379e7Schristos       /* Seen line terminator CR or CR/LF.  */
338*946379e7Schristos       if (c == '\r' || c1 == '\n')
339*946379e7Schristos 	{
340*946379e7Schristos 	  ++line_number;
341*946379e7Schristos 	  return '\n';
342*946379e7Schristos 	}
343*946379e7Schristos       else
344*946379e7Schristos 	return UNICODE ('\n');
345*946379e7Schristos     }
346*946379e7Schristos   else if (RED (c) == '\n')
347*946379e7Schristos     {
348*946379e7Schristos       /* Seen line terminator LF.  */
349*946379e7Schristos       if (c == '\n')
350*946379e7Schristos 	{
351*946379e7Schristos 	  ++line_number;
352*946379e7Schristos 	  return '\n';
353*946379e7Schristos 	}
354*946379e7Schristos       else
355*946379e7Schristos 	return UNICODE ('\n');
356*946379e7Schristos     }
357*946379e7Schristos 
358*946379e7Schristos   return c;
359*946379e7Schristos }
360*946379e7Schristos 
361*946379e7Schristos /* Supports 2 characters of pushback.  */
362*946379e7Schristos static void
phase3_ungetc(int c)363*946379e7Schristos phase3_ungetc (int c)
364*946379e7Schristos {
365*946379e7Schristos   if (c != P2_EOF)
366*946379e7Schristos     {
367*946379e7Schristos       if (c == '\n')
368*946379e7Schristos 	--line_number;
369*946379e7Schristos       if (phase3_pushback_length == SIZEOF (phase3_pushback))
370*946379e7Schristos 	abort ();
371*946379e7Schristos       phase3_pushback[phase3_pushback_length++] = c;
372*946379e7Schristos     }
373*946379e7Schristos }
374*946379e7Schristos 
375*946379e7Schristos 
376*946379e7Schristos /* ========================= Accumulating strings.  ======================== */
377*946379e7Schristos 
378*946379e7Schristos /* A string buffer type that allows appending bytes (in the
379*946379e7Schristos    xgettext_current_source_encoding) or Unicode characters.
380*946379e7Schristos    Returns the entire string in UTF-8 encoding.  */
381*946379e7Schristos 
382*946379e7Schristos struct string_buffer
383*946379e7Schristos {
384*946379e7Schristos   /* The part of the string that has already been converted to UTF-8.  */
385*946379e7Schristos   char *utf8_buffer;
386*946379e7Schristos   size_t utf8_buflen;
387*946379e7Schristos   size_t utf8_allocated;
388*946379e7Schristos   /* The first half of an UTF-16 surrogate character.  */
389*946379e7Schristos   unsigned short utf16_surr;
390*946379e7Schristos   /* The part of the string that is still in the source encoding.  */
391*946379e7Schristos   char *curr_buffer;
392*946379e7Schristos   size_t curr_buflen;
393*946379e7Schristos   size_t curr_allocated;
394*946379e7Schristos };
395*946379e7Schristos 
396*946379e7Schristos /* Initialize a 'struct string_buffer' to empty.  */
397*946379e7Schristos static inline void
init_string_buffer(struct string_buffer * bp)398*946379e7Schristos init_string_buffer (struct string_buffer *bp)
399*946379e7Schristos {
400*946379e7Schristos   bp->utf8_buffer = NULL;
401*946379e7Schristos   bp->utf8_buflen = 0;
402*946379e7Schristos   bp->utf8_allocated = 0;
403*946379e7Schristos   bp->utf16_surr = 0;
404*946379e7Schristos   bp->curr_buffer = NULL;
405*946379e7Schristos   bp->curr_buflen = 0;
406*946379e7Schristos   bp->curr_allocated = 0;
407*946379e7Schristos }
408*946379e7Schristos 
409*946379e7Schristos /* Auxiliary function: Append a byte to bp->curr.  */
410*946379e7Schristos static inline void
string_buffer_append_byte(struct string_buffer * bp,unsigned char c)411*946379e7Schristos string_buffer_append_byte (struct string_buffer *bp, unsigned char c)
412*946379e7Schristos {
413*946379e7Schristos   if (bp->curr_buflen == bp->curr_allocated)
414*946379e7Schristos     {
415*946379e7Schristos       bp->curr_allocated = 2 * bp->curr_allocated + 10;
416*946379e7Schristos       bp->curr_buffer = xrealloc (bp->curr_buffer, bp->curr_allocated);
417*946379e7Schristos     }
418*946379e7Schristos   bp->curr_buffer[bp->curr_buflen++] = c;
419*946379e7Schristos }
420*946379e7Schristos 
421*946379e7Schristos /* Auxiliary function: Ensure count more bytes are available in bp->utf8.  */
422*946379e7Schristos static inline void
string_buffer_append_unicode_grow(struct string_buffer * bp,size_t count)423*946379e7Schristos string_buffer_append_unicode_grow (struct string_buffer *bp, size_t count)
424*946379e7Schristos {
425*946379e7Schristos   if (bp->utf8_buflen + count > bp->utf8_allocated)
426*946379e7Schristos     {
427*946379e7Schristos       size_t new_allocated = 2 * bp->utf8_allocated + 10;
428*946379e7Schristos       if (new_allocated < bp->utf8_buflen + count)
429*946379e7Schristos 	new_allocated = bp->utf8_buflen + count;
430*946379e7Schristos       bp->utf8_allocated = new_allocated;
431*946379e7Schristos       bp->utf8_buffer = xrealloc (bp->utf8_buffer, new_allocated);
432*946379e7Schristos     }
433*946379e7Schristos }
434*946379e7Schristos 
435*946379e7Schristos /* Auxiliary function: Append a Unicode character to bp->utf8.
436*946379e7Schristos    uc must be < 0x110000.  */
437*946379e7Schristos static inline void
string_buffer_append_unicode(struct string_buffer * bp,unsigned int uc)438*946379e7Schristos string_buffer_append_unicode (struct string_buffer *bp, unsigned int uc)
439*946379e7Schristos {
440*946379e7Schristos   unsigned char utf8buf[6];
441*946379e7Schristos   int count = u8_uctomb (utf8buf, uc, 6);
442*946379e7Schristos 
443*946379e7Schristos   if (count < 0)
444*946379e7Schristos     /* The caller should have ensured that uc is not out-of-range.  */
445*946379e7Schristos     abort ();
446*946379e7Schristos 
447*946379e7Schristos   string_buffer_append_unicode_grow (bp, count);
448*946379e7Schristos   memcpy (bp->utf8_buffer + bp->utf8_buflen, utf8buf, count);
449*946379e7Schristos   bp->utf8_buflen += count;
450*946379e7Schristos }
451*946379e7Schristos 
452*946379e7Schristos /* Auxiliary function: Flush bp->utf16_surr into bp->utf8_buffer.  */
453*946379e7Schristos static inline void
string_buffer_flush_utf16_surr(struct string_buffer * bp)454*946379e7Schristos string_buffer_flush_utf16_surr (struct string_buffer *bp)
455*946379e7Schristos {
456*946379e7Schristos   if (bp->utf16_surr != 0)
457*946379e7Schristos     {
458*946379e7Schristos       /* A half surrogate is invalid, therefore use U+FFFD instead.  */
459*946379e7Schristos       string_buffer_append_unicode (bp, 0xfffd);
460*946379e7Schristos       bp->utf16_surr = 0;
461*946379e7Schristos     }
462*946379e7Schristos }
463*946379e7Schristos 
464*946379e7Schristos /* Auxiliary function: Flush bp->curr_buffer into bp->utf8_buffer.  */
465*946379e7Schristos static inline void
string_buffer_flush_curr_buffer(struct string_buffer * bp,int lineno)466*946379e7Schristos string_buffer_flush_curr_buffer (struct string_buffer *bp, int lineno)
467*946379e7Schristos {
468*946379e7Schristos   if (bp->curr_buflen > 0)
469*946379e7Schristos     {
470*946379e7Schristos       char *curr;
471*946379e7Schristos       size_t count;
472*946379e7Schristos 
473*946379e7Schristos       string_buffer_append_byte (bp, '\0');
474*946379e7Schristos 
475*946379e7Schristos       /* Convert from the source encoding to UTF-8.  */
476*946379e7Schristos       curr = from_current_source_encoding (bp->curr_buffer,
477*946379e7Schristos 					   logical_file_name, lineno);
478*946379e7Schristos 
479*946379e7Schristos       /* Append it to bp->utf8_buffer.  */
480*946379e7Schristos       count = strlen (curr);
481*946379e7Schristos       string_buffer_append_unicode_grow (bp, count);
482*946379e7Schristos       memcpy (bp->utf8_buffer + bp->utf8_buflen, curr, count);
483*946379e7Schristos       bp->utf8_buflen += count;
484*946379e7Schristos 
485*946379e7Schristos       if (curr != bp->curr_buffer)
486*946379e7Schristos 	free (curr);
487*946379e7Schristos       bp->curr_buflen = 0;
488*946379e7Schristos     }
489*946379e7Schristos }
490*946379e7Schristos 
491*946379e7Schristos /* Append a character or Unicode character to a 'struct string_buffer'.  */
492*946379e7Schristos static void
string_buffer_append(struct string_buffer * bp,int c)493*946379e7Schristos string_buffer_append (struct string_buffer *bp, int c)
494*946379e7Schristos {
495*946379e7Schristos   if (IS_UNICODE (c))
496*946379e7Schristos     {
497*946379e7Schristos       /* Append a Unicode character.  */
498*946379e7Schristos 
499*946379e7Schristos       /* Switch from multibyte character mode to Unicode character mode.  */
500*946379e7Schristos       string_buffer_flush_curr_buffer (bp, line_number);
501*946379e7Schristos 
502*946379e7Schristos       /* Test whether this character and the previous one form a Unicode
503*946379e7Schristos 	 surrogate character pair.  */
504*946379e7Schristos       if (bp->utf16_surr != 0
505*946379e7Schristos 	  && (c >= UNICODE (0xdc00) && c < UNICODE (0xe000)))
506*946379e7Schristos 	{
507*946379e7Schristos 	  unsigned short utf16buf[2];
508*946379e7Schristos 	  unsigned int uc;
509*946379e7Schristos 
510*946379e7Schristos 	  utf16buf[0] = bp->utf16_surr;
511*946379e7Schristos 	  utf16buf[1] = UTF16_VALUE (c);
512*946379e7Schristos 	  if (u16_mbtouc_aux (&uc, utf16buf, 2) != 2)
513*946379e7Schristos 	    abort ();
514*946379e7Schristos 
515*946379e7Schristos 	  string_buffer_append_unicode (bp, uc);
516*946379e7Schristos 	  bp->utf16_surr = 0;
517*946379e7Schristos 	}
518*946379e7Schristos       else
519*946379e7Schristos 	{
520*946379e7Schristos 	  string_buffer_flush_utf16_surr (bp);
521*946379e7Schristos 
522*946379e7Schristos 	  if (c >= UNICODE (0xd800) && c < UNICODE (0xdc00))
523*946379e7Schristos 	    bp->utf16_surr = UTF16_VALUE (c);
524*946379e7Schristos 	  else
525*946379e7Schristos 	    string_buffer_append_unicode (bp, UTF16_VALUE (c));
526*946379e7Schristos 	}
527*946379e7Schristos     }
528*946379e7Schristos   else
529*946379e7Schristos     {
530*946379e7Schristos       /* Append a single byte.  */
531*946379e7Schristos 
532*946379e7Schristos       /* Switch from Unicode character mode to multibyte character mode.  */
533*946379e7Schristos       string_buffer_flush_utf16_surr (bp);
534*946379e7Schristos 
535*946379e7Schristos       /* When a newline is seen, convert the accumulated multibyte sequence.
536*946379e7Schristos 	 This ensures a correct line number in the error message in case of
537*946379e7Schristos 	 a conversion error.  The "- 1" is to account for the newline.  */
538*946379e7Schristos       if (c == '\n')
539*946379e7Schristos 	string_buffer_flush_curr_buffer (bp, line_number - 1);
540*946379e7Schristos 
541*946379e7Schristos       string_buffer_append_byte (bp, (unsigned char) c);
542*946379e7Schristos     }
543*946379e7Schristos }
544*946379e7Schristos 
545*946379e7Schristos /* Return the string buffer's contents.  */
546*946379e7Schristos static char *
string_buffer_result(struct string_buffer * bp)547*946379e7Schristos string_buffer_result (struct string_buffer *bp)
548*946379e7Schristos {
549*946379e7Schristos   /* Flush all into bp->utf8_buffer.  */
550*946379e7Schristos   string_buffer_flush_utf16_surr (bp);
551*946379e7Schristos   string_buffer_flush_curr_buffer (bp, line_number);
552*946379e7Schristos   /* NUL-terminate it.  */
553*946379e7Schristos   string_buffer_append_unicode_grow (bp, 1);
554*946379e7Schristos   bp->utf8_buffer[bp->utf8_buflen] = '\0';
555*946379e7Schristos   /* Return it.  */
556*946379e7Schristos   return bp->utf8_buffer;
557*946379e7Schristos }
558*946379e7Schristos 
559*946379e7Schristos /* Free the memory pointed to by a 'struct string_buffer'.  */
560*946379e7Schristos static inline void
free_string_buffer(struct string_buffer * bp)561*946379e7Schristos free_string_buffer (struct string_buffer *bp)
562*946379e7Schristos {
563*946379e7Schristos   free (bp->utf8_buffer);
564*946379e7Schristos   free (bp->curr_buffer);
565*946379e7Schristos }
566*946379e7Schristos 
567*946379e7Schristos 
568*946379e7Schristos /* ======================== Accumulating comments.  ======================== */
569*946379e7Schristos 
570*946379e7Schristos 
571*946379e7Schristos /* Accumulating a single comment line.  */
572*946379e7Schristos 
573*946379e7Schristos static struct string_buffer comment_buffer;
574*946379e7Schristos 
575*946379e7Schristos static inline void
comment_start()576*946379e7Schristos comment_start ()
577*946379e7Schristos {
578*946379e7Schristos   comment_buffer.utf8_buflen = 0;
579*946379e7Schristos   comment_buffer.utf16_surr = 0;
580*946379e7Schristos   comment_buffer.curr_buflen = 0;
581*946379e7Schristos }
582*946379e7Schristos 
583*946379e7Schristos static inline bool
comment_at_start()584*946379e7Schristos comment_at_start ()
585*946379e7Schristos {
586*946379e7Schristos   return (comment_buffer.utf8_buflen == 0 && comment_buffer.utf16_surr == 0
587*946379e7Schristos 	  && comment_buffer.curr_buflen == 0);
588*946379e7Schristos }
589*946379e7Schristos 
590*946379e7Schristos static inline void
comment_add(int c)591*946379e7Schristos comment_add (int c)
592*946379e7Schristos {
593*946379e7Schristos   string_buffer_append (&comment_buffer, c);
594*946379e7Schristos }
595*946379e7Schristos 
596*946379e7Schristos static inline void
comment_line_end(size_t chars_to_remove)597*946379e7Schristos comment_line_end (size_t chars_to_remove)
598*946379e7Schristos {
599*946379e7Schristos   char *buffer = string_buffer_result (&comment_buffer);
600*946379e7Schristos   size_t buflen = strlen (buffer);
601*946379e7Schristos 
602*946379e7Schristos   buflen -= chars_to_remove;
603*946379e7Schristos   while (buflen >= 1
604*946379e7Schristos 	 && (buffer[buflen - 1] == ' ' || buffer[buflen - 1] == '\t'))
605*946379e7Schristos     --buflen;
606*946379e7Schristos   buffer[buflen] = '\0';
607*946379e7Schristos   savable_comment_add (buffer);
608*946379e7Schristos }
609*946379e7Schristos 
610*946379e7Schristos 
611*946379e7Schristos /* These are for tracking whether comments count as immediately before
612*946379e7Schristos    keyword.  */
613*946379e7Schristos static int last_comment_line;
614*946379e7Schristos static int last_non_comment_line;
615*946379e7Schristos 
616*946379e7Schristos 
617*946379e7Schristos /* Replace each comment that is not inside a character constant or string
618*946379e7Schristos    literal with a space or newline character.  */
619*946379e7Schristos 
620*946379e7Schristos static int
phase4_getc()621*946379e7Schristos phase4_getc ()
622*946379e7Schristos {
623*946379e7Schristos   int c0;
624*946379e7Schristos   int c;
625*946379e7Schristos   bool last_was_star;
626*946379e7Schristos 
627*946379e7Schristos   c0 = phase3_getc ();
628*946379e7Schristos   if (RED (c0) != '/')
629*946379e7Schristos     return c0;
630*946379e7Schristos   c = phase3_getc ();
631*946379e7Schristos   switch (RED (c))
632*946379e7Schristos     {
633*946379e7Schristos     default:
634*946379e7Schristos       phase3_ungetc (c);
635*946379e7Schristos       return c0;
636*946379e7Schristos 
637*946379e7Schristos     case '*':
638*946379e7Schristos       /* C style comment.  */
639*946379e7Schristos       comment_start ();
640*946379e7Schristos       last_was_star = false;
641*946379e7Schristos       for (;;)
642*946379e7Schristos 	{
643*946379e7Schristos 	  c = phase3_getc ();
644*946379e7Schristos 	  if (c == P2_EOF)
645*946379e7Schristos 	    break;
646*946379e7Schristos 	  /* We skip all leading white space, but not EOLs.  */
647*946379e7Schristos 	  if (!(comment_at_start () && (RED (c) == ' ' || RED (c) == '\t')))
648*946379e7Schristos 	    comment_add (c);
649*946379e7Schristos 	  switch (RED (c))
650*946379e7Schristos 	    {
651*946379e7Schristos 	    case '\n':
652*946379e7Schristos 	      comment_line_end (1);
653*946379e7Schristos 	      comment_start ();
654*946379e7Schristos 	      last_was_star = false;
655*946379e7Schristos 	      continue;
656*946379e7Schristos 
657*946379e7Schristos 	    case '*':
658*946379e7Schristos 	      last_was_star = true;
659*946379e7Schristos 	      continue;
660*946379e7Schristos 
661*946379e7Schristos 	    case '/':
662*946379e7Schristos 	      if (last_was_star)
663*946379e7Schristos 		{
664*946379e7Schristos 		  comment_line_end (2);
665*946379e7Schristos 		  break;
666*946379e7Schristos 		}
667*946379e7Schristos 	      /* FALLTHROUGH */
668*946379e7Schristos 
669*946379e7Schristos 	    default:
670*946379e7Schristos 	      last_was_star = false;
671*946379e7Schristos 	      continue;
672*946379e7Schristos 	    }
673*946379e7Schristos 	  break;
674*946379e7Schristos 	}
675*946379e7Schristos       last_comment_line = line_number;
676*946379e7Schristos       return ' ';
677*946379e7Schristos 
678*946379e7Schristos     case '/':
679*946379e7Schristos       /* C++ style comment.  */
680*946379e7Schristos       last_comment_line = line_number;
681*946379e7Schristos       comment_start ();
682*946379e7Schristos       for (;;)
683*946379e7Schristos 	{
684*946379e7Schristos 	  c = phase3_getc ();
685*946379e7Schristos 	  if (RED (c) == '\n' || c == P2_EOF)
686*946379e7Schristos 	    break;
687*946379e7Schristos 	  /* We skip all leading white space, but not EOLs.  */
688*946379e7Schristos 	  if (!(comment_at_start () && (RED (c) == ' ' || RED (c) == '\t')))
689*946379e7Schristos 	    comment_add (c);
690*946379e7Schristos 	}
691*946379e7Schristos       phase3_ungetc (c); /* push back the newline, to decrement line_number */
692*946379e7Schristos       comment_line_end (0);
693*946379e7Schristos       phase3_getc (); /* read the newline again */
694*946379e7Schristos       return '\n';
695*946379e7Schristos     }
696*946379e7Schristos }
697*946379e7Schristos 
698*946379e7Schristos /* Supports only one pushback character.  */
699*946379e7Schristos static void
phase4_ungetc(int c)700*946379e7Schristos phase4_ungetc (int c)
701*946379e7Schristos {
702*946379e7Schristos   phase3_ungetc (c);
703*946379e7Schristos }
704*946379e7Schristos 
705*946379e7Schristos 
706*946379e7Schristos /* ========================== Reading of tokens.  ========================== */
707*946379e7Schristos 
708*946379e7Schristos enum token_type_ty
709*946379e7Schristos {
710*946379e7Schristos   token_type_eof,
711*946379e7Schristos   token_type_lparen,		/* ( */
712*946379e7Schristos   token_type_rparen,		/* ) */
713*946379e7Schristos   token_type_lbrace,		/* { */
714*946379e7Schristos   token_type_rbrace,		/* } */
715*946379e7Schristos   token_type_comma,		/* , */
716*946379e7Schristos   token_type_dot,		/* . */
717*946379e7Schristos   token_type_string_literal,	/* "abc" */
718*946379e7Schristos   token_type_number,		/* 1.23 */
719*946379e7Schristos   token_type_symbol,		/* identifier, keyword, null */
720*946379e7Schristos   token_type_plus,		/* + */
721*946379e7Schristos   token_type_other		/* character literal, misc. operator */
722*946379e7Schristos };
723*946379e7Schristos typedef enum token_type_ty token_type_ty;
724*946379e7Schristos 
725*946379e7Schristos typedef struct token_ty token_ty;
726*946379e7Schristos struct token_ty
727*946379e7Schristos {
728*946379e7Schristos   token_type_ty type;
729*946379e7Schristos   char *string;		/* for token_type_string_literal, token_type_symbol */
730*946379e7Schristos   refcounted_string_list_ty *comment;	/* for token_type_string_literal */
731*946379e7Schristos   int line_number;
732*946379e7Schristos };
733*946379e7Schristos 
734*946379e7Schristos 
735*946379e7Schristos /* Free the memory pointed to by a 'struct token_ty'.  */
736*946379e7Schristos static inline void
free_token(token_ty * tp)737*946379e7Schristos free_token (token_ty *tp)
738*946379e7Schristos {
739*946379e7Schristos   if (tp->type == token_type_string_literal || tp->type == token_type_symbol)
740*946379e7Schristos     free (tp->string);
741*946379e7Schristos   if (tp->type == token_type_string_literal)
742*946379e7Schristos     drop_reference (tp->comment);
743*946379e7Schristos }
744*946379e7Schristos 
745*946379e7Schristos 
746*946379e7Schristos /* Read an escape sequence inside a string literal or character literal.  */
747*946379e7Schristos static inline int
do_getc_escaped()748*946379e7Schristos do_getc_escaped ()
749*946379e7Schristos {
750*946379e7Schristos   int c;
751*946379e7Schristos 
752*946379e7Schristos   /* Use phase 3, because phase 4 elides comments.  */
753*946379e7Schristos   c = phase3_getc ();
754*946379e7Schristos   if (c == P2_EOF)
755*946379e7Schristos     return UNICODE ('\\');
756*946379e7Schristos   switch (RED (c))
757*946379e7Schristos     {
758*946379e7Schristos     case 'b':
759*946379e7Schristos       return UNICODE (0x08);
760*946379e7Schristos     case 't':
761*946379e7Schristos       return UNICODE (0x09);
762*946379e7Schristos     case 'n':
763*946379e7Schristos       return UNICODE (0x0a);
764*946379e7Schristos     case 'f':
765*946379e7Schristos       return UNICODE (0x0c);
766*946379e7Schristos     case 'r':
767*946379e7Schristos       return UNICODE (0x0d);
768*946379e7Schristos     case '"':
769*946379e7Schristos       return UNICODE ('"');
770*946379e7Schristos     case '\'':
771*946379e7Schristos       return UNICODE ('\'');
772*946379e7Schristos     case '\\':
773*946379e7Schristos       return UNICODE ('\\');
774*946379e7Schristos     case '0': case '1': case '2': case '3':
775*946379e7Schristos     case '4': case '5': case '6': case '7':
776*946379e7Schristos       {
777*946379e7Schristos 	int n = RED (c) - '0';
778*946379e7Schristos 	bool maybe3digits = (n < 4);
779*946379e7Schristos 
780*946379e7Schristos 	c = phase3_getc ();
781*946379e7Schristos 	if (RED (c) >= '0' && RED (c) <= '7')
782*946379e7Schristos 	  {
783*946379e7Schristos 	    n = (n << 3) + (RED (c) - '0');
784*946379e7Schristos 	    if (maybe3digits)
785*946379e7Schristos 	      {
786*946379e7Schristos 		c = phase3_getc ();
787*946379e7Schristos 		if (RED (c) >= '0' && RED (c) <= '7')
788*946379e7Schristos 		  n = (n << 3) + (RED (c) - '0');
789*946379e7Schristos 		else
790*946379e7Schristos 		  phase3_ungetc (c);
791*946379e7Schristos 	      }
792*946379e7Schristos 	  }
793*946379e7Schristos 	else
794*946379e7Schristos 	  phase3_ungetc (c);
795*946379e7Schristos 
796*946379e7Schristos 	return UNICODE (n);
797*946379e7Schristos       }
798*946379e7Schristos     default:
799*946379e7Schristos       /* Invalid escape sequence.  */
800*946379e7Schristos       phase3_ungetc (c);
801*946379e7Schristos       return UNICODE ('\\');
802*946379e7Schristos     }
803*946379e7Schristos }
804*946379e7Schristos 
805*946379e7Schristos /* Read a string literal or character literal.  */
806*946379e7Schristos static void
accumulate_escaped(struct string_buffer * literal,int delimiter)807*946379e7Schristos accumulate_escaped (struct string_buffer *literal, int delimiter)
808*946379e7Schristos {
809*946379e7Schristos   int c;
810*946379e7Schristos 
811*946379e7Schristos   for (;;)
812*946379e7Schristos     {
813*946379e7Schristos       /* Use phase 3, because phase 4 elides comments.  */
814*946379e7Schristos       c = phase3_getc ();
815*946379e7Schristos       if (c == P2_EOF || RED (c) == delimiter)
816*946379e7Schristos 	break;
817*946379e7Schristos       if (RED (c) == '\n')
818*946379e7Schristos 	{
819*946379e7Schristos 	  phase3_ungetc (c);
820*946379e7Schristos 	  error_with_progname = false;
821*946379e7Schristos 	  if (delimiter == '\'')
822*946379e7Schristos 	    error (0, 0, _("%s:%d: warning: unterminated character constant"),
823*946379e7Schristos 		   logical_file_name, line_number);
824*946379e7Schristos 	  else
825*946379e7Schristos 	    error (0, 0, _("%s:%d: warning: unterminated string constant"),
826*946379e7Schristos 		   logical_file_name, line_number);
827*946379e7Schristos 	  error_with_progname = true;
828*946379e7Schristos 	  break;
829*946379e7Schristos 	}
830*946379e7Schristos       if (RED (c) == '\\')
831*946379e7Schristos 	c = do_getc_escaped ();
832*946379e7Schristos       string_buffer_append (literal, c);
833*946379e7Schristos     }
834*946379e7Schristos }
835*946379e7Schristos 
836*946379e7Schristos 
837*946379e7Schristos /* Combine characters into tokens.  Discard whitespace.  */
838*946379e7Schristos 
839*946379e7Schristos static token_ty phase5_pushback[3];
840*946379e7Schristos static int phase5_pushback_length;
841*946379e7Schristos 
842*946379e7Schristos static void
phase5_get(token_ty * tp)843*946379e7Schristos phase5_get (token_ty *tp)
844*946379e7Schristos {
845*946379e7Schristos   int c;
846*946379e7Schristos 
847*946379e7Schristos   if (phase5_pushback_length)
848*946379e7Schristos     {
849*946379e7Schristos       *tp = phase5_pushback[--phase5_pushback_length];
850*946379e7Schristos       return;
851*946379e7Schristos     }
852*946379e7Schristos   tp->string = NULL;
853*946379e7Schristos 
854*946379e7Schristos   for (;;)
855*946379e7Schristos     {
856*946379e7Schristos       tp->line_number = line_number;
857*946379e7Schristos       c = phase4_getc ();
858*946379e7Schristos 
859*946379e7Schristos       if (c == P2_EOF)
860*946379e7Schristos 	{
861*946379e7Schristos 	  tp->type = token_type_eof;
862*946379e7Schristos 	  return;
863*946379e7Schristos 	}
864*946379e7Schristos 
865*946379e7Schristos       switch (RED (c))
866*946379e7Schristos 	{
867*946379e7Schristos 	case '\n':
868*946379e7Schristos 	  if (last_non_comment_line > last_comment_line)
869*946379e7Schristos 	    savable_comment_reset ();
870*946379e7Schristos 	  /* FALLTHROUGH */
871*946379e7Schristos 	case ' ':
872*946379e7Schristos 	case '\t':
873*946379e7Schristos 	case '\f':
874*946379e7Schristos 	  /* Ignore whitespace and comments.  */
875*946379e7Schristos 	  continue;
876*946379e7Schristos 	}
877*946379e7Schristos 
878*946379e7Schristos       last_non_comment_line = tp->line_number;
879*946379e7Schristos 
880*946379e7Schristos       switch (RED (c))
881*946379e7Schristos 	{
882*946379e7Schristos 	case '(':
883*946379e7Schristos 	  tp->type = token_type_lparen;
884*946379e7Schristos 	  return;
885*946379e7Schristos 
886*946379e7Schristos 	case ')':
887*946379e7Schristos 	  tp->type = token_type_rparen;
888*946379e7Schristos 	  return;
889*946379e7Schristos 
890*946379e7Schristos 	case '{':
891*946379e7Schristos 	  tp->type = token_type_lbrace;
892*946379e7Schristos 	  return;
893*946379e7Schristos 
894*946379e7Schristos 	case '}':
895*946379e7Schristos 	  tp->type = token_type_rbrace;
896*946379e7Schristos 	  return;
897*946379e7Schristos 
898*946379e7Schristos 	case ',':
899*946379e7Schristos 	  tp->type = token_type_comma;
900*946379e7Schristos 	  return;
901*946379e7Schristos 
902*946379e7Schristos 	case '.':
903*946379e7Schristos 	  c = phase4_getc ();
904*946379e7Schristos 	  if (!(RED (c) >= '0' && RED (c) <= '9'))
905*946379e7Schristos 	    {
906*946379e7Schristos 	      phase4_ungetc (c);
907*946379e7Schristos 	      tp->type = token_type_dot;
908*946379e7Schristos 	      return;
909*946379e7Schristos 	    }
910*946379e7Schristos 	  /* FALLTHROUGH */
911*946379e7Schristos 
912*946379e7Schristos 	case '0': case '1': case '2': case '3': case '4':
913*946379e7Schristos 	case '5': case '6': case '7': case '8': case '9':
914*946379e7Schristos 	  {
915*946379e7Schristos 	    /* Don't need to verify the complicated syntax of integers and
916*946379e7Schristos 	       floating-point numbers.  We assume a valid Java input.
917*946379e7Schristos 	       The simplified syntax that we recognize as number is: any
918*946379e7Schristos 	       sequence of alphanumeric characters, additionally '+' and '-'
919*946379e7Schristos 	       immediately after 'e' or 'E' except in hexadecimal numbers.  */
920*946379e7Schristos 	    bool hexadecimal = false;
921*946379e7Schristos 
922*946379e7Schristos 	    for (;;)
923*946379e7Schristos 	      {
924*946379e7Schristos 		c = phase4_getc ();
925*946379e7Schristos 		if (RED (c) >= '0' && RED (c) <= '9')
926*946379e7Schristos 		  continue;
927*946379e7Schristos 		if ((RED (c) >= 'A' && RED (c) <= 'Z')
928*946379e7Schristos 		    || (RED (c) >= 'a' && RED (c) <= 'z'))
929*946379e7Schristos 		  {
930*946379e7Schristos 		    if (RED (c) == 'X' || RED (c) == 'x')
931*946379e7Schristos 		      hexadecimal = true;
932*946379e7Schristos 		    if ((RED (c) == 'E' || RED (c) == 'e') && !hexadecimal)
933*946379e7Schristos 		      {
934*946379e7Schristos 			c = phase4_getc ();
935*946379e7Schristos 			if (!(RED (c) == '+' || RED (c) == '-'))
936*946379e7Schristos 			  phase4_ungetc (c);
937*946379e7Schristos 		      }
938*946379e7Schristos 		    continue;
939*946379e7Schristos 		  }
940*946379e7Schristos 		if (RED (c) == '.')
941*946379e7Schristos 		  continue;
942*946379e7Schristos 		break;
943*946379e7Schristos 	      }
944*946379e7Schristos 	    phase4_ungetc (c);
945*946379e7Schristos 	    tp->type = token_type_number;
946*946379e7Schristos 	    return;
947*946379e7Schristos 	  }
948*946379e7Schristos 
949*946379e7Schristos 	case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G':
950*946379e7Schristos 	case 'H': case 'I': case 'J': case 'K': case 'L': case 'M': case 'N':
951*946379e7Schristos 	case 'O': case 'P': case 'Q': case 'R': case 'S': case 'T': case 'U':
952*946379e7Schristos 	case 'V': case 'W': case 'X': case 'Y': case 'Z':
953*946379e7Schristos 	case '_':
954*946379e7Schristos 	case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'g':
955*946379e7Schristos 	case 'h': case 'i': case 'j': case 'k': case 'l': case 'm': case 'n':
956*946379e7Schristos 	case 'o': case 'p': case 'q': case 'r': case 's': case 't': case 'u':
957*946379e7Schristos 	case 'v': case 'w': case 'x': case 'y': case 'z':
958*946379e7Schristos 	  /* Although Java allows identifiers containing many Unicode
959*946379e7Schristos 	     characters, we recognize only identifiers consisting of ASCII
960*946379e7Schristos 	     characters.  This avoids conversion hassles w.r.t. the --keyword
961*946379e7Schristos 	     arguments, and shouldn't be a big problem in practice.  */
962*946379e7Schristos 	  {
963*946379e7Schristos 	    static char *buffer;
964*946379e7Schristos 	    static int bufmax;
965*946379e7Schristos 	    int bufpos = 0;
966*946379e7Schristos 	    for (;;)
967*946379e7Schristos 	      {
968*946379e7Schristos 		if (bufpos >= bufmax)
969*946379e7Schristos 		  {
970*946379e7Schristos 		    bufmax = 2 * bufmax + 10;
971*946379e7Schristos 		    buffer = xrealloc (buffer, bufmax);
972*946379e7Schristos 		  }
973*946379e7Schristos 		buffer[bufpos++] = RED (c);
974*946379e7Schristos 		c = phase4_getc ();
975*946379e7Schristos 		if (!((RED (c) >= 'A' && RED (c) <= 'Z')
976*946379e7Schristos 		      || (RED (c) >= 'a' && RED (c) <= 'z')
977*946379e7Schristos 		      || (RED (c) >= '0' && RED (c) <= '9')
978*946379e7Schristos 		      || RED (c) == '_'))
979*946379e7Schristos 		  break;
980*946379e7Schristos 	      }
981*946379e7Schristos 	    phase4_ungetc (c);
982*946379e7Schristos 	    if (bufpos >= bufmax)
983*946379e7Schristos 	      {
984*946379e7Schristos 		bufmax = 2 * bufmax + 10;
985*946379e7Schristos 		buffer = xrealloc (buffer, bufmax);
986*946379e7Schristos 	      }
987*946379e7Schristos 	    buffer[bufpos] = '\0';
988*946379e7Schristos 	    tp->string = xstrdup (buffer);
989*946379e7Schristos 	    tp->type = token_type_symbol;
990*946379e7Schristos 	    return;
991*946379e7Schristos 	  }
992*946379e7Schristos 
993*946379e7Schristos 	case '"':
994*946379e7Schristos 	  /* String literal.  */
995*946379e7Schristos 	  {
996*946379e7Schristos 	    struct string_buffer literal;
997*946379e7Schristos 
998*946379e7Schristos 	    init_string_buffer (&literal);
999*946379e7Schristos 	    accumulate_escaped (&literal, '"');
1000*946379e7Schristos 	    tp->string = xstrdup (string_buffer_result (&literal));
1001*946379e7Schristos 	    free_string_buffer (&literal);
1002*946379e7Schristos 	    tp->comment = add_reference (savable_comment);
1003*946379e7Schristos 	    tp->type = token_type_string_literal;
1004*946379e7Schristos 	    return;
1005*946379e7Schristos 	  }
1006*946379e7Schristos 
1007*946379e7Schristos 	case '\'':
1008*946379e7Schristos 	  /* Character literal.  */
1009*946379e7Schristos 	  {
1010*946379e7Schristos 	    struct string_buffer literal;
1011*946379e7Schristos 
1012*946379e7Schristos 	    init_string_buffer (&literal);
1013*946379e7Schristos 	    accumulate_escaped (&literal, '\'');
1014*946379e7Schristos 	    free_string_buffer (&literal);
1015*946379e7Schristos 	    tp->type = token_type_other;
1016*946379e7Schristos 	    return;
1017*946379e7Schristos 	  }
1018*946379e7Schristos 
1019*946379e7Schristos 	case '+':
1020*946379e7Schristos 	  c = phase4_getc ();
1021*946379e7Schristos 	  if (RED (c) == '+')
1022*946379e7Schristos 	    /* Operator ++ */
1023*946379e7Schristos 	    tp->type = token_type_other;
1024*946379e7Schristos 	  else if (RED (c) == '=')
1025*946379e7Schristos 	    /* Operator += */
1026*946379e7Schristos 	    tp->type = token_type_other;
1027*946379e7Schristos 	  else
1028*946379e7Schristos 	    {
1029*946379e7Schristos 	      /* Operator + */
1030*946379e7Schristos 	      phase4_ungetc (c);
1031*946379e7Schristos 	      tp->type = token_type_plus;
1032*946379e7Schristos 	    }
1033*946379e7Schristos 	  return;
1034*946379e7Schristos 
1035*946379e7Schristos 	default:
1036*946379e7Schristos 	  /* Misc. operator.  */
1037*946379e7Schristos 	  tp->type = token_type_other;
1038*946379e7Schristos 	  return;
1039*946379e7Schristos 	}
1040*946379e7Schristos     }
1041*946379e7Schristos }
1042*946379e7Schristos 
1043*946379e7Schristos /* Supports 3 tokens of pushback.  */
1044*946379e7Schristos static void
phase5_unget(token_ty * tp)1045*946379e7Schristos phase5_unget (token_ty *tp)
1046*946379e7Schristos {
1047*946379e7Schristos   if (tp->type != token_type_eof)
1048*946379e7Schristos     {
1049*946379e7Schristos       if (phase5_pushback_length == SIZEOF (phase5_pushback))
1050*946379e7Schristos 	abort ();
1051*946379e7Schristos       phase5_pushback[phase5_pushback_length++] = *tp;
1052*946379e7Schristos     }
1053*946379e7Schristos }
1054*946379e7Schristos 
1055*946379e7Schristos 
1056*946379e7Schristos /* Compile-time optimization of string literal concatenation.
1057*946379e7Schristos    Combine "string1" + ... + "stringN" to the concatenated string if
1058*946379e7Schristos      - the token before this expression is not ')' (because then the first
1059*946379e7Schristos        string could be part of a cast expression),
1060*946379e7Schristos      - the token after this expression is not '.' (because then the last
1061*946379e7Schristos        string could be part of a method call expression).  */
1062*946379e7Schristos 
1063*946379e7Schristos static token_ty phase6_pushback[2];
1064*946379e7Schristos static int phase6_pushback_length;
1065*946379e7Schristos 
1066*946379e7Schristos static token_type_ty phase6_last;
1067*946379e7Schristos 
1068*946379e7Schristos static void
phase6_get(token_ty * tp)1069*946379e7Schristos phase6_get (token_ty *tp)
1070*946379e7Schristos {
1071*946379e7Schristos   if (phase6_pushback_length)
1072*946379e7Schristos     {
1073*946379e7Schristos       *tp = phase6_pushback[--phase6_pushback_length];
1074*946379e7Schristos       return;
1075*946379e7Schristos     }
1076*946379e7Schristos 
1077*946379e7Schristos   phase5_get (tp);
1078*946379e7Schristos   if (tp->type == token_type_string_literal && phase6_last != token_type_rparen)
1079*946379e7Schristos     {
1080*946379e7Schristos       char *sum = tp->string;
1081*946379e7Schristos       size_t sum_len = strlen (sum);
1082*946379e7Schristos 
1083*946379e7Schristos       for (;;)
1084*946379e7Schristos 	{
1085*946379e7Schristos 	  token_ty token2;
1086*946379e7Schristos 
1087*946379e7Schristos 	  phase5_get (&token2);
1088*946379e7Schristos 	  if (token2.type == token_type_plus)
1089*946379e7Schristos 	    {
1090*946379e7Schristos 	      token_ty token3;
1091*946379e7Schristos 
1092*946379e7Schristos 	      phase5_get (&token3);
1093*946379e7Schristos 	      if (token3.type == token_type_string_literal)
1094*946379e7Schristos 		{
1095*946379e7Schristos 		  token_ty token_after;
1096*946379e7Schristos 
1097*946379e7Schristos 		  phase5_get (&token_after);
1098*946379e7Schristos 		  if (token_after.type != token_type_dot)
1099*946379e7Schristos 		    {
1100*946379e7Schristos 		      char *addend = token3.string;
1101*946379e7Schristos 		      size_t addend_len = strlen (addend);
1102*946379e7Schristos 
1103*946379e7Schristos 		      sum = (char *) xrealloc (sum, sum_len + addend_len + 1);
1104*946379e7Schristos 		      memcpy (sum + sum_len, addend, addend_len + 1);
1105*946379e7Schristos 		      sum_len += addend_len;
1106*946379e7Schristos 
1107*946379e7Schristos 		      phase5_unget (&token_after);
1108*946379e7Schristos 		      free_token (&token3);
1109*946379e7Schristos 		      free_token (&token2);
1110*946379e7Schristos 		      continue;
1111*946379e7Schristos 		    }
1112*946379e7Schristos 		  phase5_unget (&token_after);
1113*946379e7Schristos 		}
1114*946379e7Schristos 	      phase5_unget (&token3);
1115*946379e7Schristos 	    }
1116*946379e7Schristos 	  phase5_unget (&token2);
1117*946379e7Schristos 	  break;
1118*946379e7Schristos 	}
1119*946379e7Schristos       tp->string = sum;
1120*946379e7Schristos     }
1121*946379e7Schristos   phase6_last = tp->type;
1122*946379e7Schristos }
1123*946379e7Schristos 
1124*946379e7Schristos /* Supports 2 tokens of pushback.  */
1125*946379e7Schristos static void
phase6_unget(token_ty * tp)1126*946379e7Schristos phase6_unget (token_ty *tp)
1127*946379e7Schristos {
1128*946379e7Schristos   if (tp->type != token_type_eof)
1129*946379e7Schristos     {
1130*946379e7Schristos       if (phase6_pushback_length == SIZEOF (phase6_pushback))
1131*946379e7Schristos 	abort ();
1132*946379e7Schristos       phase6_pushback[phase6_pushback_length++] = *tp;
1133*946379e7Schristos     }
1134*946379e7Schristos }
1135*946379e7Schristos 
1136*946379e7Schristos 
1137*946379e7Schristos static void
x_java_lex(token_ty * tp)1138*946379e7Schristos x_java_lex (token_ty *tp)
1139*946379e7Schristos {
1140*946379e7Schristos   phase6_get (tp);
1141*946379e7Schristos }
1142*946379e7Schristos 
1143*946379e7Schristos /* Supports 2 tokens of pushback.  */
1144*946379e7Schristos static void
x_java_unlex(token_ty * tp)1145*946379e7Schristos x_java_unlex (token_ty *tp)
1146*946379e7Schristos {
1147*946379e7Schristos   phase6_unget (tp);
1148*946379e7Schristos }
1149*946379e7Schristos 
1150*946379e7Schristos 
1151*946379e7Schristos /* ========================= Extracting strings.  ========================== */
1152*946379e7Schristos 
1153*946379e7Schristos 
1154*946379e7Schristos /* Context lookup table.  */
1155*946379e7Schristos static flag_context_list_table_ty *flag_context_list_table;
1156*946379e7Schristos 
1157*946379e7Schristos 
1158*946379e7Schristos /* The file is broken into tokens.  Scan the token stream, looking for
1159*946379e7Schristos    a keyword, followed by a left paren, followed by a string.  When we
1160*946379e7Schristos    see this sequence, we have something to remember.  We assume we are
1161*946379e7Schristos    looking at a valid C or C++ program, and leave the complaints about
1162*946379e7Schristos    the grammar to the compiler.
1163*946379e7Schristos 
1164*946379e7Schristos      Normal handling: Look for
1165*946379e7Schristos        keyword ( ... msgid ... )
1166*946379e7Schristos      Plural handling: Look for
1167*946379e7Schristos        keyword ( ... msgid ... msgid_plural ... )
1168*946379e7Schristos 
1169*946379e7Schristos    We use recursion because the arguments before msgid or between msgid
1170*946379e7Schristos    and msgid_plural can contain subexpressions of the same form.  */
1171*946379e7Schristos 
1172*946379e7Schristos 
1173*946379e7Schristos /* Extract messages until the next balanced closing parenthesis or brace,
1174*946379e7Schristos    depending on TERMINATOR.
1175*946379e7Schristos    Extracted messages are added to MLP.
1176*946379e7Schristos    Return true upon eof, false upon closing parenthesis or brace.  */
1177*946379e7Schristos static bool
extract_parenthesized(message_list_ty * mlp,token_type_ty terminator,flag_context_ty outer_context,flag_context_list_iterator_ty context_iter,struct arglist_parser * argparser)1178*946379e7Schristos extract_parenthesized (message_list_ty *mlp, token_type_ty terminator,
1179*946379e7Schristos 		       flag_context_ty outer_context,
1180*946379e7Schristos 		       flag_context_list_iterator_ty context_iter,
1181*946379e7Schristos 		       struct arglist_parser *argparser)
1182*946379e7Schristos {
1183*946379e7Schristos   /* Current argument number.  */
1184*946379e7Schristos   int arg = 1;
1185*946379e7Schristos   /* 0 when no keyword has been seen.  1 right after a keyword is seen.  */
1186*946379e7Schristos   int state;
1187*946379e7Schristos   /* Parameters of the keyword just seen.  Defined only in state 1.  */
1188*946379e7Schristos   const struct callshapes *next_shapes = NULL;
1189*946379e7Schristos   /* Context iterator that will be used if the next token is a '('.  */
1190*946379e7Schristos   flag_context_list_iterator_ty next_context_iter =
1191*946379e7Schristos     passthrough_context_list_iterator;
1192*946379e7Schristos   /* Current context.  */
1193*946379e7Schristos   flag_context_ty inner_context =
1194*946379e7Schristos     inherited_context (outer_context,
1195*946379e7Schristos 		       flag_context_list_iterator_advance (&context_iter));
1196*946379e7Schristos 
1197*946379e7Schristos   /* Start state is 0.  */
1198*946379e7Schristos   state = 0;
1199*946379e7Schristos 
1200*946379e7Schristos   for (;;)
1201*946379e7Schristos     {
1202*946379e7Schristos       token_ty token;
1203*946379e7Schristos 
1204*946379e7Schristos       x_java_lex (&token);
1205*946379e7Schristos       switch (token.type)
1206*946379e7Schristos 	{
1207*946379e7Schristos 	case token_type_symbol:
1208*946379e7Schristos 	  {
1209*946379e7Schristos 	    /* Combine symbol1 . ... . symbolN to a single strings, so that
1210*946379e7Schristos 	       we can recognize static function calls like
1211*946379e7Schristos 	       GettextResource.gettext.  The information present for
1212*946379e7Schristos 	       symbolI.....symbolN has precedence over the information for
1213*946379e7Schristos 	       symbolJ.....symbolN with J > I.  */
1214*946379e7Schristos 	    char *sum = token.string;
1215*946379e7Schristos 	    size_t sum_len = strlen (sum);
1216*946379e7Schristos 	    const char *dottedname;
1217*946379e7Schristos 	    flag_context_list_ty *context_list;
1218*946379e7Schristos 
1219*946379e7Schristos 	    for (;;)
1220*946379e7Schristos 	      {
1221*946379e7Schristos 		token_ty token2;
1222*946379e7Schristos 
1223*946379e7Schristos 		x_java_lex (&token2);
1224*946379e7Schristos 		if (token2.type == token_type_dot)
1225*946379e7Schristos 		  {
1226*946379e7Schristos 		    token_ty token3;
1227*946379e7Schristos 
1228*946379e7Schristos 		    x_java_lex (&token3);
1229*946379e7Schristos 		    if (token3.type == token_type_symbol)
1230*946379e7Schristos 		      {
1231*946379e7Schristos 			char *addend = token3.string;
1232*946379e7Schristos 			size_t addend_len = strlen (addend);
1233*946379e7Schristos 
1234*946379e7Schristos 			sum =
1235*946379e7Schristos 			  (char *) xrealloc (sum, sum_len + 1 + addend_len + 1);
1236*946379e7Schristos 			sum[sum_len] = '.';
1237*946379e7Schristos 			memcpy (sum + sum_len + 1, addend, addend_len + 1);
1238*946379e7Schristos 			sum_len += 1 + addend_len;
1239*946379e7Schristos 
1240*946379e7Schristos 			free_token (&token3);
1241*946379e7Schristos 			free_token (&token2);
1242*946379e7Schristos 			continue;
1243*946379e7Schristos 		      }
1244*946379e7Schristos 		    x_java_unlex (&token3);
1245*946379e7Schristos 		  }
1246*946379e7Schristos 		x_java_unlex (&token2);
1247*946379e7Schristos 		break;
1248*946379e7Schristos 	      }
1249*946379e7Schristos 
1250*946379e7Schristos 	    for (dottedname = sum;;)
1251*946379e7Schristos 	      {
1252*946379e7Schristos 		void *keyword_value;
1253*946379e7Schristos 
1254*946379e7Schristos 		if (hash_find_entry (&keywords, dottedname, strlen (dottedname),
1255*946379e7Schristos 				     &keyword_value)
1256*946379e7Schristos 		    == 0)
1257*946379e7Schristos 		  {
1258*946379e7Schristos 		    next_shapes = (const struct callshapes *) keyword_value;
1259*946379e7Schristos 		    state = 1;
1260*946379e7Schristos 		    break;
1261*946379e7Schristos 		  }
1262*946379e7Schristos 
1263*946379e7Schristos 		dottedname = strchr (dottedname, '.');
1264*946379e7Schristos 		if (dottedname == NULL)
1265*946379e7Schristos 		  {
1266*946379e7Schristos 		    state = 0;
1267*946379e7Schristos 		    break;
1268*946379e7Schristos 		  }
1269*946379e7Schristos 		dottedname++;
1270*946379e7Schristos 	      }
1271*946379e7Schristos 
1272*946379e7Schristos 	    for (dottedname = sum;;)
1273*946379e7Schristos 	      {
1274*946379e7Schristos 		context_list =
1275*946379e7Schristos 		  flag_context_list_table_lookup (
1276*946379e7Schristos 		    flag_context_list_table,
1277*946379e7Schristos 		    dottedname, strlen (dottedname));
1278*946379e7Schristos 		if (context_list != NULL)
1279*946379e7Schristos 		  break;
1280*946379e7Schristos 
1281*946379e7Schristos 		dottedname = strchr (dottedname, '.');
1282*946379e7Schristos 		if (dottedname == NULL)
1283*946379e7Schristos 		  break;
1284*946379e7Schristos 		dottedname++;
1285*946379e7Schristos 	      }
1286*946379e7Schristos 	    next_context_iter = flag_context_list_iterator (context_list);
1287*946379e7Schristos 
1288*946379e7Schristos 	    free (sum);
1289*946379e7Schristos 	    continue;
1290*946379e7Schristos 	  }
1291*946379e7Schristos 
1292*946379e7Schristos 	case token_type_lparen:
1293*946379e7Schristos 	  if (extract_parenthesized (mlp, token_type_rparen,
1294*946379e7Schristos 				     inner_context, next_context_iter,
1295*946379e7Schristos 				     arglist_parser_alloc (mlp,
1296*946379e7Schristos 							   state ? next_shapes : NULL)))
1297*946379e7Schristos 	    {
1298*946379e7Schristos 	      xgettext_current_source_encoding = po_charset_utf8;
1299*946379e7Schristos 	      arglist_parser_done (argparser, arg);
1300*946379e7Schristos 	      xgettext_current_source_encoding = xgettext_global_source_encoding;
1301*946379e7Schristos 	      return true;
1302*946379e7Schristos 	    }
1303*946379e7Schristos 	  next_context_iter = null_context_list_iterator;
1304*946379e7Schristos 	  state = 0;
1305*946379e7Schristos 	  continue;
1306*946379e7Schristos 
1307*946379e7Schristos 	case token_type_rparen:
1308*946379e7Schristos 	  if (terminator == token_type_rparen)
1309*946379e7Schristos 	    {
1310*946379e7Schristos 	      xgettext_current_source_encoding = po_charset_utf8;
1311*946379e7Schristos 	      arglist_parser_done (argparser, arg);
1312*946379e7Schristos 	      xgettext_current_source_encoding = xgettext_global_source_encoding;
1313*946379e7Schristos 	      return false;
1314*946379e7Schristos 	    }
1315*946379e7Schristos 	  if (terminator == token_type_rbrace)
1316*946379e7Schristos 	    {
1317*946379e7Schristos 	      error_with_progname = false;
1318*946379e7Schristos 	      error (0, 0,
1319*946379e7Schristos 		     _("%s:%d: warning: ')' found where '}' was expected"),
1320*946379e7Schristos 		     logical_file_name, token.line_number);
1321*946379e7Schristos 	      error_with_progname = true;
1322*946379e7Schristos 	    }
1323*946379e7Schristos 	  next_context_iter = null_context_list_iterator;
1324*946379e7Schristos 	  state = 0;
1325*946379e7Schristos 	  continue;
1326*946379e7Schristos 
1327*946379e7Schristos 	case token_type_lbrace:
1328*946379e7Schristos 	  if (extract_parenthesized (mlp, token_type_rbrace,
1329*946379e7Schristos 				     null_context, null_context_list_iterator,
1330*946379e7Schristos 				     arglist_parser_alloc (mlp, NULL)))
1331*946379e7Schristos 	    {
1332*946379e7Schristos 	      xgettext_current_source_encoding = po_charset_utf8;
1333*946379e7Schristos 	      arglist_parser_done (argparser, arg);
1334*946379e7Schristos 	      xgettext_current_source_encoding = xgettext_global_source_encoding;
1335*946379e7Schristos 	      return true;
1336*946379e7Schristos 	    }
1337*946379e7Schristos 	  next_context_iter = null_context_list_iterator;
1338*946379e7Schristos 	  state = 0;
1339*946379e7Schristos 	  continue;
1340*946379e7Schristos 
1341*946379e7Schristos 	case token_type_rbrace:
1342*946379e7Schristos 	  if (terminator == token_type_rbrace)
1343*946379e7Schristos 	    {
1344*946379e7Schristos 	      xgettext_current_source_encoding = po_charset_utf8;
1345*946379e7Schristos 	      arglist_parser_done (argparser, arg);
1346*946379e7Schristos 	      xgettext_current_source_encoding = xgettext_global_source_encoding;
1347*946379e7Schristos 	      return false;
1348*946379e7Schristos 	    }
1349*946379e7Schristos 	  if (terminator == token_type_rparen)
1350*946379e7Schristos 	    {
1351*946379e7Schristos 	      error_with_progname = false;
1352*946379e7Schristos 	      error (0, 0,
1353*946379e7Schristos 		     _("%s:%d: warning: '}' found where ')' was expected"),
1354*946379e7Schristos 		     logical_file_name, token.line_number);
1355*946379e7Schristos 	      error_with_progname = true;
1356*946379e7Schristos 	    }
1357*946379e7Schristos 	  next_context_iter = null_context_list_iterator;
1358*946379e7Schristos 	  state = 0;
1359*946379e7Schristos 	  continue;
1360*946379e7Schristos 
1361*946379e7Schristos 	case token_type_comma:
1362*946379e7Schristos 	  arg++;
1363*946379e7Schristos 	  inner_context =
1364*946379e7Schristos 	    inherited_context (outer_context,
1365*946379e7Schristos 			       flag_context_list_iterator_advance (
1366*946379e7Schristos 				 &context_iter));
1367*946379e7Schristos 	  next_context_iter = passthrough_context_list_iterator;
1368*946379e7Schristos 	  state = 0;
1369*946379e7Schristos 	  continue;
1370*946379e7Schristos 
1371*946379e7Schristos 	case token_type_string_literal:
1372*946379e7Schristos 	  {
1373*946379e7Schristos 	    lex_pos_ty pos;
1374*946379e7Schristos 	    pos.file_name = logical_file_name;
1375*946379e7Schristos 	    pos.line_number = token.line_number;
1376*946379e7Schristos 
1377*946379e7Schristos 	    xgettext_current_source_encoding = po_charset_utf8;
1378*946379e7Schristos 	    if (extract_all)
1379*946379e7Schristos 	      remember_a_message (mlp, NULL, token.string, inner_context,
1380*946379e7Schristos 				  &pos, token.comment);
1381*946379e7Schristos 	    else
1382*946379e7Schristos 	      arglist_parser_remember (argparser, arg, token.string,
1383*946379e7Schristos 				       inner_context,
1384*946379e7Schristos 				       pos.file_name, pos.line_number,
1385*946379e7Schristos 				       token.comment);
1386*946379e7Schristos 	    xgettext_current_source_encoding = xgettext_global_source_encoding;
1387*946379e7Schristos 	  }
1388*946379e7Schristos 	  drop_reference (token.comment);
1389*946379e7Schristos 	  next_context_iter = null_context_list_iterator;
1390*946379e7Schristos 	  state = 0;
1391*946379e7Schristos 	  continue;
1392*946379e7Schristos 
1393*946379e7Schristos 	case token_type_eof:
1394*946379e7Schristos 	  xgettext_current_source_encoding = po_charset_utf8;
1395*946379e7Schristos 	  arglist_parser_done (argparser, arg);
1396*946379e7Schristos 	  xgettext_current_source_encoding = xgettext_global_source_encoding;
1397*946379e7Schristos 	  return true;
1398*946379e7Schristos 
1399*946379e7Schristos 	case token_type_dot:
1400*946379e7Schristos 	case token_type_number:
1401*946379e7Schristos 	case token_type_plus:
1402*946379e7Schristos 	case token_type_other:
1403*946379e7Schristos 	  next_context_iter = null_context_list_iterator;
1404*946379e7Schristos 	  state = 0;
1405*946379e7Schristos 	  continue;
1406*946379e7Schristos 
1407*946379e7Schristos 	default:
1408*946379e7Schristos 	  abort ();
1409*946379e7Schristos 	}
1410*946379e7Schristos     }
1411*946379e7Schristos }
1412*946379e7Schristos 
1413*946379e7Schristos 
1414*946379e7Schristos void
extract_java(FILE * f,const char * real_filename,const char * logical_filename,flag_context_list_table_ty * flag_table,msgdomain_list_ty * mdlp)1415*946379e7Schristos extract_java (FILE *f,
1416*946379e7Schristos 	      const char *real_filename, const char *logical_filename,
1417*946379e7Schristos 	      flag_context_list_table_ty *flag_table,
1418*946379e7Schristos 	      msgdomain_list_ty *mdlp)
1419*946379e7Schristos {
1420*946379e7Schristos   message_list_ty *mlp = mdlp->item[0]->messages;
1421*946379e7Schristos 
1422*946379e7Schristos   fp = f;
1423*946379e7Schristos   real_file_name = real_filename;
1424*946379e7Schristos   logical_file_name = xstrdup (logical_filename);
1425*946379e7Schristos   line_number = 1;
1426*946379e7Schristos 
1427*946379e7Schristos   last_comment_line = -1;
1428*946379e7Schristos   last_non_comment_line = -1;
1429*946379e7Schristos 
1430*946379e7Schristos   phase6_last = token_type_eof;
1431*946379e7Schristos 
1432*946379e7Schristos   flag_context_list_table = flag_table;
1433*946379e7Schristos 
1434*946379e7Schristos   init_keywords ();
1435*946379e7Schristos 
1436*946379e7Schristos   /* Eat tokens until eof is seen.  When extract_parenthesized returns
1437*946379e7Schristos      due to an unbalanced closing parenthesis, just restart it.  */
1438*946379e7Schristos   while (!extract_parenthesized (mlp, token_type_eof,
1439*946379e7Schristos 				 null_context, null_context_list_iterator,
1440*946379e7Schristos 				 arglist_parser_alloc (mlp, NULL)))
1441*946379e7Schristos     ;
1442*946379e7Schristos 
1443*946379e7Schristos   fp = NULL;
1444*946379e7Schristos   real_file_name = NULL;
1445*946379e7Schristos   logical_file_name = NULL;
1446*946379e7Schristos   line_number = 0;
1447*946379e7Schristos }
1448