xref: /netbsd-src/external/gpl2/gettext/dist/gettext-tools/src/x-python.c (revision 946379e7b37692fc43f68eb0d1c10daa0a7f3b6c)
1*946379e7Schristos /* xgettext Python backend.
2*946379e7Schristos    Copyright (C) 2002-2003, 2005-2006 Free Software Foundation, Inc.
3*946379e7Schristos 
4*946379e7Schristos    This file was written by Bruno Haible <haible@clisp.cons.org>, 2002.
5*946379e7Schristos 
6*946379e7Schristos    This program is free software; you can redistribute it and/or modify
7*946379e7Schristos    it under the terms of the GNU General Public License as published by
8*946379e7Schristos    the Free Software Foundation; either version 2, or (at your option)
9*946379e7Schristos    any later version.
10*946379e7Schristos 
11*946379e7Schristos    This program is distributed in the hope that it will be useful,
12*946379e7Schristos    but WITHOUT ANY WARRANTY; without even the implied warranty of
13*946379e7Schristos    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14*946379e7Schristos    GNU General Public License for more details.
15*946379e7Schristos 
16*946379e7Schristos    You should have received a copy of the GNU General Public License
17*946379e7Schristos    along with this program; if not, write to the Free Software Foundation,
18*946379e7Schristos    Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.  */
19*946379e7Schristos 
20*946379e7Schristos #ifdef HAVE_CONFIG_H
21*946379e7Schristos # include "config.h"
22*946379e7Schristos #endif
23*946379e7Schristos 
24*946379e7Schristos #include <assert.h>
25*946379e7Schristos #include <errno.h>
26*946379e7Schristos #include <stdbool.h>
27*946379e7Schristos #include <stdio.h>
28*946379e7Schristos #include <stdlib.h>
29*946379e7Schristos #include <string.h>
30*946379e7Schristos 
31*946379e7Schristos #include "message.h"
32*946379e7Schristos #include "xgettext.h"
33*946379e7Schristos #include "x-python.h"
34*946379e7Schristos #include "error.h"
35*946379e7Schristos #include "error-progname.h"
36*946379e7Schristos #include "progname.h"
37*946379e7Schristos #include "basename.h"
38*946379e7Schristos #include "xerror.h"
39*946379e7Schristos #include "xvasprintf.h"
40*946379e7Schristos #include "xalloc.h"
41*946379e7Schristos #include "exit.h"
42*946379e7Schristos #include "c-strstr.h"
43*946379e7Schristos #include "c-ctype.h"
44*946379e7Schristos #include "po-charset.h"
45*946379e7Schristos #include "uniname.h"
46*946379e7Schristos #include "utf16-ucs4.h"
47*946379e7Schristos #include "utf8-ucs4.h"
48*946379e7Schristos #include "ucs4-utf8.h"
49*946379e7Schristos #include "gettext.h"
50*946379e7Schristos 
51*946379e7Schristos #define _(s) gettext(s)
52*946379e7Schristos 
53*946379e7Schristos #define max(a,b) ((a) > (b) ? (a) : (b))
54*946379e7Schristos 
55*946379e7Schristos #define SIZEOF(a) (sizeof(a) / sizeof(a[0]))
56*946379e7Schristos 
57*946379e7Schristos 
58*946379e7Schristos /* The Python syntax is defined in the Python Reference Manual
59*946379e7Schristos    /usr/share/doc/packages/python/html/ref/index.html.
60*946379e7Schristos    See also Python-2.0/Parser/tokenizer.c, Python-2.0/Python/compile.c,
61*946379e7Schristos    Python-2.0/Objects/unicodeobject.c.  */
62*946379e7Schristos 
63*946379e7Schristos 
64*946379e7Schristos /* ====================== Keyword set customization.  ====================== */
65*946379e7Schristos 
66*946379e7Schristos /* If true extract all strings.  */
67*946379e7Schristos static bool extract_all = false;
68*946379e7Schristos 
69*946379e7Schristos static hash_table keywords;
70*946379e7Schristos static bool default_keywords = true;
71*946379e7Schristos 
72*946379e7Schristos 
73*946379e7Schristos void
x_python_extract_all()74*946379e7Schristos x_python_extract_all ()
75*946379e7Schristos {
76*946379e7Schristos   extract_all = true;
77*946379e7Schristos }
78*946379e7Schristos 
79*946379e7Schristos 
80*946379e7Schristos void
x_python_keyword(const char * name)81*946379e7Schristos x_python_keyword (const char *name)
82*946379e7Schristos {
83*946379e7Schristos   if (name == NULL)
84*946379e7Schristos     default_keywords = false;
85*946379e7Schristos   else
86*946379e7Schristos     {
87*946379e7Schristos       const char *end;
88*946379e7Schristos       struct callshape shape;
89*946379e7Schristos       const char *colon;
90*946379e7Schristos 
91*946379e7Schristos       if (keywords.table == NULL)
92*946379e7Schristos 	hash_init (&keywords, 100);
93*946379e7Schristos 
94*946379e7Schristos       split_keywordspec (name, &end, &shape);
95*946379e7Schristos 
96*946379e7Schristos       /* The characters between name and end should form a valid C identifier.
97*946379e7Schristos 	 A colon means an invalid parse in split_keywordspec().  */
98*946379e7Schristos       colon = strchr (name, ':');
99*946379e7Schristos       if (colon == NULL || colon >= end)
100*946379e7Schristos 	insert_keyword_callshape (&keywords, name, end - name, &shape);
101*946379e7Schristos     }
102*946379e7Schristos }
103*946379e7Schristos 
104*946379e7Schristos /* Finish initializing the keywords hash table.
105*946379e7Schristos    Called after argument processing, before each file is processed.  */
106*946379e7Schristos static void
init_keywords()107*946379e7Schristos init_keywords ()
108*946379e7Schristos {
109*946379e7Schristos   if (default_keywords)
110*946379e7Schristos     {
111*946379e7Schristos       /* When adding new keywords here, also update the documentation in
112*946379e7Schristos 	 xgettext.texi!  */
113*946379e7Schristos       x_python_keyword ("gettext");
114*946379e7Schristos       x_python_keyword ("ugettext");
115*946379e7Schristos       x_python_keyword ("dgettext:2");
116*946379e7Schristos       x_python_keyword ("ngettext:1,2");
117*946379e7Schristos       x_python_keyword ("ungettext:1,2");
118*946379e7Schristos       x_python_keyword ("dngettext:2,3");
119*946379e7Schristos       x_python_keyword ("_");
120*946379e7Schristos       default_keywords = false;
121*946379e7Schristos     }
122*946379e7Schristos }
123*946379e7Schristos 
124*946379e7Schristos void
init_flag_table_python()125*946379e7Schristos init_flag_table_python ()
126*946379e7Schristos {
127*946379e7Schristos   xgettext_record_flag ("gettext:1:pass-python-format");
128*946379e7Schristos   xgettext_record_flag ("ugettext:1:pass-python-format");
129*946379e7Schristos   xgettext_record_flag ("dgettext:2:pass-python-format");
130*946379e7Schristos   xgettext_record_flag ("ngettext:1:pass-python-format");
131*946379e7Schristos   xgettext_record_flag ("ngettext:2:pass-python-format");
132*946379e7Schristos   xgettext_record_flag ("ungettext:1:pass-python-format");
133*946379e7Schristos   xgettext_record_flag ("ungettext:2:pass-python-format");
134*946379e7Schristos   xgettext_record_flag ("dngettext:2:pass-python-format");
135*946379e7Schristos   xgettext_record_flag ("dngettext:3:pass-python-format");
136*946379e7Schristos   xgettext_record_flag ("_:1:pass-python-format");
137*946379e7Schristos   /* xgettext_record_flag ("%:1:python-format"); // % is an infix operator! */
138*946379e7Schristos }
139*946379e7Schristos 
140*946379e7Schristos 
141*946379e7Schristos /* ======================== Reading of characters.  ======================== */
142*946379e7Schristos 
143*946379e7Schristos /* Real filename, used in error messages about the input file.  */
144*946379e7Schristos static const char *real_file_name;
145*946379e7Schristos 
146*946379e7Schristos /* Logical filename and line number, used to label the extracted messages.  */
147*946379e7Schristos static char *logical_file_name;
148*946379e7Schristos static int line_number;
149*946379e7Schristos 
150*946379e7Schristos /* The input file stream.  */
151*946379e7Schristos static FILE *fp;
152*946379e7Schristos 
153*946379e7Schristos 
154*946379e7Schristos /* 1. line_number handling.  */
155*946379e7Schristos 
156*946379e7Schristos /* Maximum used, roughly a safer MB_LEN_MAX.  */
157*946379e7Schristos #define MAX_PHASE1_PUSHBACK 16
158*946379e7Schristos static unsigned char phase1_pushback[MAX_PHASE1_PUSHBACK];
159*946379e7Schristos static int phase1_pushback_length;
160*946379e7Schristos 
161*946379e7Schristos /* Read the next single byte from the input file.  */
162*946379e7Schristos static int
phase1_getc()163*946379e7Schristos phase1_getc ()
164*946379e7Schristos {
165*946379e7Schristos   int c;
166*946379e7Schristos 
167*946379e7Schristos   if (phase1_pushback_length)
168*946379e7Schristos     c = phase1_pushback[--phase1_pushback_length];
169*946379e7Schristos   else
170*946379e7Schristos     {
171*946379e7Schristos       c = getc (fp);
172*946379e7Schristos 
173*946379e7Schristos       if (c == EOF)
174*946379e7Schristos 	{
175*946379e7Schristos 	  if (ferror (fp))
176*946379e7Schristos 	    error (EXIT_FAILURE, errno, _("error while reading \"%s\""),
177*946379e7Schristos 		   real_file_name);
178*946379e7Schristos 	  return EOF;
179*946379e7Schristos 	}
180*946379e7Schristos     }
181*946379e7Schristos 
182*946379e7Schristos   if (c == '\n')
183*946379e7Schristos     ++line_number;
184*946379e7Schristos 
185*946379e7Schristos   return c;
186*946379e7Schristos }
187*946379e7Schristos 
188*946379e7Schristos /* Supports MAX_PHASE1_PUSHBACK characters of pushback.  */
189*946379e7Schristos static void
phase1_ungetc(int c)190*946379e7Schristos phase1_ungetc (int c)
191*946379e7Schristos {
192*946379e7Schristos   if (c != EOF)
193*946379e7Schristos     {
194*946379e7Schristos       if (c == '\n')
195*946379e7Schristos 	--line_number;
196*946379e7Schristos 
197*946379e7Schristos       if (phase1_pushback_length == SIZEOF (phase1_pushback))
198*946379e7Schristos 	abort ();
199*946379e7Schristos       phase1_pushback[phase1_pushback_length++] = c;
200*946379e7Schristos     }
201*946379e7Schristos }
202*946379e7Schristos 
203*946379e7Schristos 
204*946379e7Schristos /* Phase 2: Conversion to Unicode.
205*946379e7Schristos    This is done early because PEP 0263 specifies that conversion to Unicode
206*946379e7Schristos    conceptually occurs before tokenization.  A test case where it matters
207*946379e7Schristos    is with encodings like BIG5: when a double-byte character ending in 0x5C
208*946379e7Schristos    is followed by '\' or 'u0021', the tokenizer must not treat the second
209*946379e7Schristos    half of the double-byte character as a backslash.  */
210*946379e7Schristos 
211*946379e7Schristos /* End-of-file indicator for functions returning an UCS-4 character.  */
212*946379e7Schristos #define UEOF -1
213*946379e7Schristos 
214*946379e7Schristos static int phase2_pushback[max (9, UNINAME_MAX + 3)];
215*946379e7Schristos static int phase2_pushback_length;
216*946379e7Schristos 
217*946379e7Schristos /* Read the next Unicode UCS-4 character from the input file.  */
218*946379e7Schristos static int
phase2_getc()219*946379e7Schristos phase2_getc ()
220*946379e7Schristos {
221*946379e7Schristos   if (phase2_pushback_length)
222*946379e7Schristos     return phase2_pushback[--phase2_pushback_length];
223*946379e7Schristos 
224*946379e7Schristos   if (xgettext_current_source_encoding == po_charset_ascii)
225*946379e7Schristos     {
226*946379e7Schristos       int c = phase1_getc ();
227*946379e7Schristos       if (c == EOF)
228*946379e7Schristos 	return UEOF;
229*946379e7Schristos       if (!c_isascii (c))
230*946379e7Schristos 	{
231*946379e7Schristos 	  char buffer[21];
232*946379e7Schristos 	  sprintf (buffer, ":%ld", (long) line_number);
233*946379e7Schristos 	  multiline_error (xstrdup (""),
234*946379e7Schristos 			   xasprintf (_("\
235*946379e7Schristos Non-ASCII string at %s%s.\n\
236*946379e7Schristos Please specify the source encoding through --from-code or through a comment\n\
237*946379e7Schristos as specified in http://www.python.org/peps/pep-0263.html.\n"),
238*946379e7Schristos 			   real_file_name, buffer));
239*946379e7Schristos 	  exit (EXIT_FAILURE);
240*946379e7Schristos 	}
241*946379e7Schristos       return c;
242*946379e7Schristos     }
243*946379e7Schristos   else if (xgettext_current_source_encoding != po_charset_utf8)
244*946379e7Schristos     {
245*946379e7Schristos #if HAVE_ICONV
246*946379e7Schristos       /* Use iconv on an increasing number of bytes.  Read only as many bytes
247*946379e7Schristos 	 through phase1_getc as needed.  This is needed to give reasonable
248*946379e7Schristos 	 interactive behaviour when fp is connected to an interactive tty.  */
249*946379e7Schristos       unsigned char buf[MAX_PHASE1_PUSHBACK];
250*946379e7Schristos       size_t bufcount;
251*946379e7Schristos       int c = phase1_getc ();
252*946379e7Schristos       if (c == EOF)
253*946379e7Schristos 	return UEOF;
254*946379e7Schristos       buf[0] = (unsigned char) c;
255*946379e7Schristos       bufcount = 1;
256*946379e7Schristos 
257*946379e7Schristos       for (;;)
258*946379e7Schristos 	{
259*946379e7Schristos 	  unsigned char scratchbuf[6];
260*946379e7Schristos 	  const char *inptr = (const char *) &buf[0];
261*946379e7Schristos 	  size_t insize = bufcount;
262*946379e7Schristos 	  char *outptr = (char *) &scratchbuf[0];
263*946379e7Schristos 	  size_t outsize = sizeof (scratchbuf);
264*946379e7Schristos 
265*946379e7Schristos 	  size_t res = iconv (xgettext_current_source_iconv,
266*946379e7Schristos 			      (ICONV_CONST char **) &inptr, &insize,
267*946379e7Schristos 			      &outptr, &outsize);
268*946379e7Schristos 	  /* We expect that a character has been produced if and only if
269*946379e7Schristos 	     some input bytes have been consumed.  */
270*946379e7Schristos 	  if ((insize < bufcount) != (outsize < sizeof (scratchbuf)))
271*946379e7Schristos 	    abort ();
272*946379e7Schristos 	  if (outsize == sizeof (scratchbuf))
273*946379e7Schristos 	    {
274*946379e7Schristos 	      /* No character has been produced.  Must be an error.  */
275*946379e7Schristos 	      if (res != (size_t)(-1))
276*946379e7Schristos 		abort ();
277*946379e7Schristos 
278*946379e7Schristos 	      if (errno == EILSEQ)
279*946379e7Schristos 		{
280*946379e7Schristos 		  /* An invalid multibyte sequence was encountered.  */
281*946379e7Schristos 		  multiline_error (xstrdup (""),
282*946379e7Schristos 				   xasprintf (_("\
283*946379e7Schristos %s:%d: Invalid multibyte sequence.\n\
284*946379e7Schristos Please specify the correct source encoding through --from-code or through a\n\
285*946379e7Schristos comment as specified in http://www.python.org/peps/pep-0263.html.\n"),
286*946379e7Schristos 				   real_file_name, line_number));
287*946379e7Schristos 		  exit (EXIT_FAILURE);
288*946379e7Schristos 		}
289*946379e7Schristos 	      else if (errno == EINVAL)
290*946379e7Schristos 		{
291*946379e7Schristos 		  /* An incomplete multibyte character.  */
292*946379e7Schristos 		  int c;
293*946379e7Schristos 
294*946379e7Schristos 		  if (bufcount == MAX_PHASE1_PUSHBACK)
295*946379e7Schristos 		    {
296*946379e7Schristos 		      /* An overlong incomplete multibyte sequence was
297*946379e7Schristos 			 encountered.  */
298*946379e7Schristos 		      multiline_error (xstrdup (""),
299*946379e7Schristos 				       xasprintf (_("\
300*946379e7Schristos %s:%d: Long incomplete multibyte sequence.\n\
301*946379e7Schristos Please specify the correct source encoding through --from-code or through a\n\
302*946379e7Schristos comment as specified in http://www.python.org/peps/pep-0263.html.\n"),
303*946379e7Schristos 				       real_file_name, line_number));
304*946379e7Schristos 		      exit (EXIT_FAILURE);
305*946379e7Schristos 		    }
306*946379e7Schristos 
307*946379e7Schristos 		  /* Read one more byte and retry iconv.  */
308*946379e7Schristos 		  c = phase1_getc ();
309*946379e7Schristos 		  if (c == EOF)
310*946379e7Schristos 		    {
311*946379e7Schristos 		      multiline_error (xstrdup (""),
312*946379e7Schristos 				       xasprintf (_("\
313*946379e7Schristos %s:%d: Incomplete multibyte sequence at end of file.\n\
314*946379e7Schristos Please specify the correct source encoding through --from-code or through a\n\
315*946379e7Schristos comment as specified in http://www.python.org/peps/pep-0263.html.\n"),
316*946379e7Schristos 				       real_file_name, line_number));
317*946379e7Schristos 		      exit (EXIT_FAILURE);
318*946379e7Schristos 		    }
319*946379e7Schristos 		  if (c == '\n')
320*946379e7Schristos 		    {
321*946379e7Schristos 		      multiline_error (xstrdup (""),
322*946379e7Schristos 				       xasprintf (_("\
323*946379e7Schristos %s:%d: Incomplete multibyte sequence at end of line.\n\
324*946379e7Schristos Please specify the correct source encoding through --from-code or through a\n\
325*946379e7Schristos comment as specified in http://www.python.org/peps/pep-0263.html.\n"),
326*946379e7Schristos 				       real_file_name, line_number - 1));
327*946379e7Schristos 		      exit (EXIT_FAILURE);
328*946379e7Schristos 		    }
329*946379e7Schristos 		  buf[bufcount++] = (unsigned char) c;
330*946379e7Schristos 		}
331*946379e7Schristos 	      else
332*946379e7Schristos 		error (EXIT_FAILURE, errno, _("%s:%d: iconv failure"),
333*946379e7Schristos 		       real_file_name, line_number);
334*946379e7Schristos 	    }
335*946379e7Schristos 	  else
336*946379e7Schristos 	    {
337*946379e7Schristos 	      size_t outbytes = sizeof (scratchbuf) - outsize;
338*946379e7Schristos 	      size_t bytes = bufcount - insize;
339*946379e7Schristos 	      unsigned int uc;
340*946379e7Schristos 
341*946379e7Schristos 	      /* We expect that one character has been produced.  */
342*946379e7Schristos 	      if (bytes == 0)
343*946379e7Schristos 		abort ();
344*946379e7Schristos 	      if (outbytes == 0)
345*946379e7Schristos 		abort ();
346*946379e7Schristos 	      /* Push back the unused bytes.  */
347*946379e7Schristos 	      while (insize > 0)
348*946379e7Schristos 		phase1_ungetc (buf[--insize]);
349*946379e7Schristos 	      /* Convert the character from UTF-8 to UCS-4.  */
350*946379e7Schristos 	      if (u8_mbtouc (&uc, scratchbuf, outbytes) < outbytes)
351*946379e7Schristos 		{
352*946379e7Schristos 		  /* scratchbuf contains an out-of-range Unicode character
353*946379e7Schristos 		     (> 0x10ffff).  */
354*946379e7Schristos 		  multiline_error (xstrdup (""),
355*946379e7Schristos 				   xasprintf (_("\
356*946379e7Schristos %s:%d: Invalid multibyte sequence.\n\
357*946379e7Schristos Please specify the source encoding through --from-code or through a comment\n\
358*946379e7Schristos as specified in http://www.python.org/peps/pep-0263.html.\n"),
359*946379e7Schristos 				   real_file_name, line_number));
360*946379e7Schristos 		  exit (EXIT_FAILURE);
361*946379e7Schristos 		}
362*946379e7Schristos 	      return uc;
363*946379e7Schristos 	    }
364*946379e7Schristos 	}
365*946379e7Schristos #else
366*946379e7Schristos       /* If we don't have iconv(), the only supported values for
367*946379e7Schristos 	 xgettext_global_source_encoding and thus also for
368*946379e7Schristos 	 xgettext_current_source_encoding are ASCII and UTF-8.  */
369*946379e7Schristos       abort ();
370*946379e7Schristos #endif
371*946379e7Schristos     }
372*946379e7Schristos   else
373*946379e7Schristos     {
374*946379e7Schristos       /* Read an UTF-8 encoded character.  */
375*946379e7Schristos       unsigned char buf[6];
376*946379e7Schristos       unsigned int count;
377*946379e7Schristos       int c;
378*946379e7Schristos       unsigned int uc;
379*946379e7Schristos 
380*946379e7Schristos       c = phase1_getc ();
381*946379e7Schristos       if (c == EOF)
382*946379e7Schristos 	return UEOF;
383*946379e7Schristos       buf[0] = c;
384*946379e7Schristos       count = 1;
385*946379e7Schristos 
386*946379e7Schristos       if (buf[0] >= 0xc0)
387*946379e7Schristos 	{
388*946379e7Schristos 	  c = phase1_getc ();
389*946379e7Schristos 	  if (c == EOF)
390*946379e7Schristos 	    return UEOF;
391*946379e7Schristos 	  buf[1] = c;
392*946379e7Schristos 	  count = 2;
393*946379e7Schristos 	}
394*946379e7Schristos 
395*946379e7Schristos       if (buf[0] >= 0xe0
396*946379e7Schristos 	  && ((buf[1] ^ 0x80) < 0x40))
397*946379e7Schristos 	{
398*946379e7Schristos 	  c = phase1_getc ();
399*946379e7Schristos 	  if (c == EOF)
400*946379e7Schristos 	    return UEOF;
401*946379e7Schristos 	  buf[2] = c;
402*946379e7Schristos 	  count = 3;
403*946379e7Schristos 	}
404*946379e7Schristos 
405*946379e7Schristos       if (buf[0] >= 0xf0
406*946379e7Schristos 	  && ((buf[1] ^ 0x80) < 0x40)
407*946379e7Schristos 	  && ((buf[2] ^ 0x80) < 0x40))
408*946379e7Schristos 	{
409*946379e7Schristos 	  c = phase1_getc ();
410*946379e7Schristos 	  if (c == EOF)
411*946379e7Schristos 	    return UEOF;
412*946379e7Schristos 	  buf[3] = c;
413*946379e7Schristos 	  count = 4;
414*946379e7Schristos 	}
415*946379e7Schristos 
416*946379e7Schristos       if (buf[0] >= 0xf8
417*946379e7Schristos 	  && ((buf[1] ^ 0x80) < 0x40)
418*946379e7Schristos 	  && ((buf[2] ^ 0x80) < 0x40)
419*946379e7Schristos 	  && ((buf[3] ^ 0x80) < 0x40))
420*946379e7Schristos 	{
421*946379e7Schristos 	  c = phase1_getc ();
422*946379e7Schristos 	  if (c == EOF)
423*946379e7Schristos 	    return UEOF;
424*946379e7Schristos 	  buf[4] = c;
425*946379e7Schristos 	  count = 5;
426*946379e7Schristos 	}
427*946379e7Schristos 
428*946379e7Schristos       if (buf[0] >= 0xfc
429*946379e7Schristos 	  && ((buf[1] ^ 0x80) < 0x40)
430*946379e7Schristos 	  && ((buf[2] ^ 0x80) < 0x40)
431*946379e7Schristos 	  && ((buf[3] ^ 0x80) < 0x40)
432*946379e7Schristos 	  && ((buf[4] ^ 0x80) < 0x40))
433*946379e7Schristos 	{
434*946379e7Schristos 	  c = phase1_getc ();
435*946379e7Schristos 	  if (c == EOF)
436*946379e7Schristos 	    return UEOF;
437*946379e7Schristos 	  buf[5] = c;
438*946379e7Schristos 	  count = 6;
439*946379e7Schristos 	}
440*946379e7Schristos 
441*946379e7Schristos       u8_mbtouc (&uc, buf, count);
442*946379e7Schristos       return uc;
443*946379e7Schristos     }
444*946379e7Schristos }
445*946379e7Schristos 
446*946379e7Schristos /* Supports max (9, UNINAME_MAX + 3) pushback characters.  */
447*946379e7Schristos static void
phase2_ungetc(int c)448*946379e7Schristos phase2_ungetc (int c)
449*946379e7Schristos {
450*946379e7Schristos   if (c != UEOF)
451*946379e7Schristos     {
452*946379e7Schristos       if (phase2_pushback_length == SIZEOF (phase2_pushback))
453*946379e7Schristos 	abort ();
454*946379e7Schristos       phase2_pushback[phase2_pushback_length++] = c;
455*946379e7Schristos     }
456*946379e7Schristos }
457*946379e7Schristos 
458*946379e7Schristos 
459*946379e7Schristos /* ========================= Accumulating strings.  ======================== */
460*946379e7Schristos 
461*946379e7Schristos /* A string buffer type that allows appending Unicode characters.
462*946379e7Schristos    Returns the entire string in UTF-8 encoding.  */
463*946379e7Schristos 
464*946379e7Schristos struct unicode_string_buffer
465*946379e7Schristos {
466*946379e7Schristos   /* The part of the string that has already been converted to UTF-8.  */
467*946379e7Schristos   char *utf8_buffer;
468*946379e7Schristos   size_t utf8_buflen;
469*946379e7Schristos   size_t utf8_allocated;
470*946379e7Schristos };
471*946379e7Schristos 
472*946379e7Schristos /* Initialize a 'struct unicode_string_buffer' to empty.  */
473*946379e7Schristos static inline void
init_unicode_string_buffer(struct unicode_string_buffer * bp)474*946379e7Schristos init_unicode_string_buffer (struct unicode_string_buffer *bp)
475*946379e7Schristos {
476*946379e7Schristos   bp->utf8_buffer = NULL;
477*946379e7Schristos   bp->utf8_buflen = 0;
478*946379e7Schristos   bp->utf8_allocated = 0;
479*946379e7Schristos }
480*946379e7Schristos 
481*946379e7Schristos /* Auxiliary function: Ensure count more bytes are available in bp->utf8.  */
482*946379e7Schristos static inline void
unicode_string_buffer_append_unicode_grow(struct unicode_string_buffer * bp,size_t count)483*946379e7Schristos unicode_string_buffer_append_unicode_grow (struct unicode_string_buffer *bp,
484*946379e7Schristos 					   size_t count)
485*946379e7Schristos {
486*946379e7Schristos   if (bp->utf8_buflen + count > bp->utf8_allocated)
487*946379e7Schristos     {
488*946379e7Schristos       size_t new_allocated = 2 * bp->utf8_allocated + 10;
489*946379e7Schristos       if (new_allocated < bp->utf8_buflen + count)
490*946379e7Schristos 	new_allocated = bp->utf8_buflen + count;
491*946379e7Schristos       bp->utf8_allocated = new_allocated;
492*946379e7Schristos       bp->utf8_buffer = xrealloc (bp->utf8_buffer, new_allocated);
493*946379e7Schristos     }
494*946379e7Schristos }
495*946379e7Schristos 
496*946379e7Schristos /* Auxiliary function: Append a Unicode character to bp->utf8.
497*946379e7Schristos    uc must be < 0x110000.  */
498*946379e7Schristos static inline void
unicode_string_buffer_append_unicode(struct unicode_string_buffer * bp,unsigned int uc)499*946379e7Schristos unicode_string_buffer_append_unicode (struct unicode_string_buffer *bp,
500*946379e7Schristos 				      unsigned int uc)
501*946379e7Schristos {
502*946379e7Schristos   unsigned char utf8buf[6];
503*946379e7Schristos   int count = u8_uctomb (utf8buf, uc, 6);
504*946379e7Schristos 
505*946379e7Schristos   if (count < 0)
506*946379e7Schristos     /* The caller should have ensured that uc is not out-of-range.  */
507*946379e7Schristos     abort ();
508*946379e7Schristos 
509*946379e7Schristos   unicode_string_buffer_append_unicode_grow (bp, count);
510*946379e7Schristos   memcpy (bp->utf8_buffer + bp->utf8_buflen, utf8buf, count);
511*946379e7Schristos   bp->utf8_buflen += count;
512*946379e7Schristos }
513*946379e7Schristos 
514*946379e7Schristos /* Return the string buffer's contents.  */
515*946379e7Schristos static char *
unicode_string_buffer_result(struct unicode_string_buffer * bp)516*946379e7Schristos unicode_string_buffer_result (struct unicode_string_buffer *bp)
517*946379e7Schristos {
518*946379e7Schristos   /* NUL-terminate it.  */
519*946379e7Schristos   unicode_string_buffer_append_unicode_grow (bp, 1);
520*946379e7Schristos   bp->utf8_buffer[bp->utf8_buflen] = '\0';
521*946379e7Schristos   /* Return it.  */
522*946379e7Schristos   return bp->utf8_buffer;
523*946379e7Schristos }
524*946379e7Schristos 
525*946379e7Schristos /* Free the memory pointed to by a 'struct unicode_string_buffer'.  */
526*946379e7Schristos static inline void
free_unicode_string_buffer(struct unicode_string_buffer * bp)527*946379e7Schristos free_unicode_string_buffer (struct unicode_string_buffer *bp)
528*946379e7Schristos {
529*946379e7Schristos   free (bp->utf8_buffer);
530*946379e7Schristos }
531*946379e7Schristos 
532*946379e7Schristos 
533*946379e7Schristos /* ======================== Accumulating comments.  ======================== */
534*946379e7Schristos 
535*946379e7Schristos 
536*946379e7Schristos /* Accumulating a single comment line.  */
537*946379e7Schristos 
538*946379e7Schristos static struct unicode_string_buffer comment_buffer;
539*946379e7Schristos 
540*946379e7Schristos static inline void
comment_start()541*946379e7Schristos comment_start ()
542*946379e7Schristos {
543*946379e7Schristos   comment_buffer.utf8_buflen = 0;
544*946379e7Schristos }
545*946379e7Schristos 
546*946379e7Schristos static inline bool
comment_at_start()547*946379e7Schristos comment_at_start ()
548*946379e7Schristos {
549*946379e7Schristos   return (comment_buffer.utf8_buflen == 0);
550*946379e7Schristos }
551*946379e7Schristos 
552*946379e7Schristos static inline void
comment_add(int c)553*946379e7Schristos comment_add (int c)
554*946379e7Schristos {
555*946379e7Schristos   unicode_string_buffer_append_unicode (&comment_buffer, c);
556*946379e7Schristos }
557*946379e7Schristos 
558*946379e7Schristos static inline const char *
comment_line_end()559*946379e7Schristos comment_line_end ()
560*946379e7Schristos {
561*946379e7Schristos   char *buffer = unicode_string_buffer_result (&comment_buffer);
562*946379e7Schristos   size_t buflen = strlen (buffer);
563*946379e7Schristos 
564*946379e7Schristos   while (buflen >= 1
565*946379e7Schristos 	 && (buffer[buflen - 1] == ' ' || buffer[buflen - 1] == '\t'))
566*946379e7Schristos     --buflen;
567*946379e7Schristos   buffer[buflen] = '\0';
568*946379e7Schristos   savable_comment_add (buffer);
569*946379e7Schristos   return buffer;
570*946379e7Schristos }
571*946379e7Schristos 
572*946379e7Schristos 
573*946379e7Schristos /* These are for tracking whether comments count as immediately before
574*946379e7Schristos    keyword.  */
575*946379e7Schristos static int last_comment_line;
576*946379e7Schristos static int last_non_comment_line;
577*946379e7Schristos 
578*946379e7Schristos 
579*946379e7Schristos /* ======================== Recognizing comments.  ======================== */
580*946379e7Schristos 
581*946379e7Schristos 
582*946379e7Schristos /* Recognizing the "coding" comment.
583*946379e7Schristos    As specified in PEP 0263, it takes the form
584*946379e7Schristos      "coding" [":"|"="] {alphanumeric or "-" or "_" or "*"}*
585*946379e7Schristos    and is located in a comment in a line that
586*946379e7Schristos      - is either the first or second line,
587*946379e7Schristos      - is not a continuation line,
588*946379e7Schristos      - contains no other tokens except this comment.  */
589*946379e7Schristos 
590*946379e7Schristos /* Canonicalized encoding name for the current input file.  */
591*946379e7Schristos static const char *xgettext_current_file_source_encoding;
592*946379e7Schristos 
593*946379e7Schristos #if HAVE_ICONV
594*946379e7Schristos /* Converter from xgettext_current_file_source_encoding to UTF-8 (except from
595*946379e7Schristos    ASCII or UTF-8, when this conversion is a no-op).  */
596*946379e7Schristos static iconv_t xgettext_current_file_source_iconv;
597*946379e7Schristos #endif
598*946379e7Schristos 
599*946379e7Schristos static inline void
set_current_file_source_encoding(const char * canon_encoding)600*946379e7Schristos set_current_file_source_encoding (const char *canon_encoding)
601*946379e7Schristos {
602*946379e7Schristos   xgettext_current_file_source_encoding = canon_encoding;
603*946379e7Schristos 
604*946379e7Schristos   if (xgettext_current_file_source_encoding != po_charset_ascii
605*946379e7Schristos       && xgettext_current_file_source_encoding != po_charset_utf8)
606*946379e7Schristos     {
607*946379e7Schristos #if HAVE_ICONV
608*946379e7Schristos       iconv_t cd;
609*946379e7Schristos 
610*946379e7Schristos       /* Avoid glibc-2.1 bug with EUC-KR.  */
611*946379e7Schristos # if (__GLIBC__ - 0 == 2 && __GLIBC_MINOR__ - 0 <= 1) && !defined _LIBICONV_VERSION
612*946379e7Schristos       if (strcmp (xgettext_current_file_source_encoding, "EUC-KR") == 0)
613*946379e7Schristos 	cd = (iconv_t)(-1);
614*946379e7Schristos       else
615*946379e7Schristos # endif
616*946379e7Schristos       cd = iconv_open (po_charset_utf8, xgettext_current_file_source_encoding);
617*946379e7Schristos       if (cd == (iconv_t)(-1))
618*946379e7Schristos 	error_at_line (EXIT_FAILURE, 0, logical_file_name, line_number - 1, _("\
619*946379e7Schristos Cannot convert from \"%s\" to \"%s\". %s relies on iconv(), \
620*946379e7Schristos and iconv() does not support this conversion."),
621*946379e7Schristos 	       xgettext_current_file_source_encoding, po_charset_utf8,
622*946379e7Schristos 	       basename (program_name));
623*946379e7Schristos       xgettext_current_file_source_iconv = cd;
624*946379e7Schristos #else
625*946379e7Schristos       error_at_line (EXIT_FAILURE, 0, logical_file_name, line_number - 1, _("\
626*946379e7Schristos Cannot convert from \"%s\" to \"%s\". %s relies on iconv(). \
627*946379e7Schristos This version was built without iconv()."),
628*946379e7Schristos 	     xgettext_global_source_encoding, po_charset_utf8,
629*946379e7Schristos 	     basename (program_name));
630*946379e7Schristos #endif
631*946379e7Schristos     }
632*946379e7Schristos 
633*946379e7Schristos   xgettext_current_source_encoding = xgettext_current_file_source_encoding;
634*946379e7Schristos #if HAVE_ICONV
635*946379e7Schristos   xgettext_current_source_iconv = xgettext_current_file_source_iconv;
636*946379e7Schristos #endif
637*946379e7Schristos }
638*946379e7Schristos 
639*946379e7Schristos static inline void
try_to_extract_coding(const char * comment)640*946379e7Schristos try_to_extract_coding (const char *comment)
641*946379e7Schristos {
642*946379e7Schristos   const char *p = c_strstr (comment, "coding");
643*946379e7Schristos 
644*946379e7Schristos   if (p != NULL)
645*946379e7Schristos     {
646*946379e7Schristos       p += 6;
647*946379e7Schristos       if (*p == ':' || *p == '=')
648*946379e7Schristos 	{
649*946379e7Schristos 	  p++;
650*946379e7Schristos 	  while (*p == ' ' || *p == '\t')
651*946379e7Schristos 	    p++;
652*946379e7Schristos 	  {
653*946379e7Schristos 	    const char *encoding_start = p;
654*946379e7Schristos 
655*946379e7Schristos 	    while (c_isalnum (*p) || *p == '-' || *p == '_' || *p == '.')
656*946379e7Schristos 	      p++;
657*946379e7Schristos 	    {
658*946379e7Schristos 	      const char *encoding_end = p;
659*946379e7Schristos 
660*946379e7Schristos 	      if (encoding_end > encoding_start)
661*946379e7Schristos 		{
662*946379e7Schristos 		  /* Extract the encoding string.  */
663*946379e7Schristos 		  size_t encoding_len = encoding_end - encoding_start;
664*946379e7Schristos 		  char *encoding = (char *) xmalloc (encoding_len + 1);
665*946379e7Schristos 
666*946379e7Schristos 		  memcpy (encoding, encoding_start, encoding_len);
667*946379e7Schristos 		  encoding[encoding_len] = '\0';
668*946379e7Schristos 
669*946379e7Schristos 		  {
670*946379e7Schristos 		    /* Canonicalize it.  */
671*946379e7Schristos 		    const char *canon_encoding = po_charset_canonicalize (encoding);
672*946379e7Schristos 		    if (canon_encoding == NULL)
673*946379e7Schristos 		      {
674*946379e7Schristos 			error_at_line (0, 0,
675*946379e7Schristos 				       logical_file_name, line_number - 1, _("\
676*946379e7Schristos Unknown encoding \"%s\". Proceeding with ASCII instead."),
677*946379e7Schristos 				       encoding);
678*946379e7Schristos 		        canon_encoding = po_charset_ascii;
679*946379e7Schristos 		      }
680*946379e7Schristos 
681*946379e7Schristos 		    /* Activate it.  */
682*946379e7Schristos 		    set_current_file_source_encoding (canon_encoding);
683*946379e7Schristos 		  }
684*946379e7Schristos 
685*946379e7Schristos 		  free (encoding);
686*946379e7Schristos 		}
687*946379e7Schristos 	    }
688*946379e7Schristos 	  }
689*946379e7Schristos 	}
690*946379e7Schristos     }
691*946379e7Schristos }
692*946379e7Schristos 
693*946379e7Schristos /* Tracking whether the current line is a continuation line or contains a
694*946379e7Schristos    non-blank character.  */
695*946379e7Schristos static bool continuation_or_nonblank_line = false;
696*946379e7Schristos 
697*946379e7Schristos 
698*946379e7Schristos /* Phase 3: Outside strings, replace backslash-newline with nothing and a
699*946379e7Schristos    comment with nothing.  */
700*946379e7Schristos 
701*946379e7Schristos static int
phase3_getc()702*946379e7Schristos phase3_getc ()
703*946379e7Schristos {
704*946379e7Schristos   int c;
705*946379e7Schristos 
706*946379e7Schristos   for (;;)
707*946379e7Schristos     {
708*946379e7Schristos       c = phase2_getc ();
709*946379e7Schristos       if (c == '\\')
710*946379e7Schristos 	{
711*946379e7Schristos 	  c = phase2_getc ();
712*946379e7Schristos 	  if (c != '\n')
713*946379e7Schristos 	    {
714*946379e7Schristos 	      phase2_ungetc (c);
715*946379e7Schristos 	      /* This shouldn't happen usually, because "A backslash is
716*946379e7Schristos 		 illegal elsewhere on a line outside a string literal."  */
717*946379e7Schristos 	      return '\\';
718*946379e7Schristos 	    }
719*946379e7Schristos 	  /* Eat backslash-newline.  */
720*946379e7Schristos 	  continuation_or_nonblank_line = true;
721*946379e7Schristos 	}
722*946379e7Schristos       else if (c == '#')
723*946379e7Schristos 	{
724*946379e7Schristos 	  /* Eat a comment.  */
725*946379e7Schristos 	  const char *comment;
726*946379e7Schristos 
727*946379e7Schristos 	  last_comment_line = line_number;
728*946379e7Schristos 	  comment_start ();
729*946379e7Schristos 	  for (;;)
730*946379e7Schristos 	    {
731*946379e7Schristos 	      c = phase2_getc ();
732*946379e7Schristos 	      if (c == UEOF || c == '\n')
733*946379e7Schristos 		break;
734*946379e7Schristos 	      /* We skip all leading white space, but not EOLs.  */
735*946379e7Schristos 	      if (!(comment_at_start () && (c == ' ' || c == '\t')))
736*946379e7Schristos 		comment_add (c);
737*946379e7Schristos 	    }
738*946379e7Schristos 	  comment = comment_line_end ();
739*946379e7Schristos 	  if (line_number - 1 <= 2 && !continuation_or_nonblank_line)
740*946379e7Schristos 	    try_to_extract_coding (comment);
741*946379e7Schristos 	  continuation_or_nonblank_line = false;
742*946379e7Schristos 	  return c;
743*946379e7Schristos 	}
744*946379e7Schristos       else
745*946379e7Schristos 	{
746*946379e7Schristos 	  if (c == '\n')
747*946379e7Schristos 	    continuation_or_nonblank_line = false;
748*946379e7Schristos 	  else if (!(c == ' ' || c == '\t' || c == '\f'))
749*946379e7Schristos 	    continuation_or_nonblank_line = true;
750*946379e7Schristos 	  return c;
751*946379e7Schristos 	}
752*946379e7Schristos     }
753*946379e7Schristos }
754*946379e7Schristos 
755*946379e7Schristos /* Supports only one pushback character.  */
756*946379e7Schristos static void
phase3_ungetc(int c)757*946379e7Schristos phase3_ungetc (int c)
758*946379e7Schristos {
759*946379e7Schristos   phase2_ungetc (c);
760*946379e7Schristos }
761*946379e7Schristos 
762*946379e7Schristos 
763*946379e7Schristos /* ========================= Accumulating strings.  ======================== */
764*946379e7Schristos 
765*946379e7Schristos /* Return value of phase7_getuc when EOF is reached.  */
766*946379e7Schristos #define P7_EOF (-1)
767*946379e7Schristos #define P7_STRING_END (-2)
768*946379e7Schristos 
769*946379e7Schristos /* Convert an UTF-16 or UTF-32 code point to a return value that can be
770*946379e7Schristos    distinguished from a single-byte return value.  */
771*946379e7Schristos #define UNICODE(code) (0x100 + (code))
772*946379e7Schristos 
773*946379e7Schristos /* Test a return value of phase7_getuc whether it designates an UTF-16 or
774*946379e7Schristos    UTF-32 code point.  */
775*946379e7Schristos #define IS_UNICODE(p7_result) ((p7_result) >= 0x100)
776*946379e7Schristos 
777*946379e7Schristos /* Extract the UTF-16 or UTF-32 code of a return value that satisfies
778*946379e7Schristos    IS_UNICODE.  */
779*946379e7Schristos #define UNICODE_VALUE(p7_result) ((p7_result) - 0x100)
780*946379e7Schristos 
781*946379e7Schristos /* A string buffer type that allows appending bytes (in the
782*946379e7Schristos    xgettext_current_source_encoding) or Unicode characters.
783*946379e7Schristos    Returns the entire string in UTF-8 encoding.  */
784*946379e7Schristos 
785*946379e7Schristos struct mixed_string_buffer
786*946379e7Schristos {
787*946379e7Schristos   /* The part of the string that has already been converted to UTF-8.  */
788*946379e7Schristos   char *utf8_buffer;
789*946379e7Schristos   size_t utf8_buflen;
790*946379e7Schristos   size_t utf8_allocated;
791*946379e7Schristos   /* The first half of an UTF-16 surrogate character.  */
792*946379e7Schristos   unsigned short utf16_surr;
793*946379e7Schristos   /* The part of the string that is still in the source encoding.  */
794*946379e7Schristos   char *curr_buffer;
795*946379e7Schristos   size_t curr_buflen;
796*946379e7Schristos   size_t curr_allocated;
797*946379e7Schristos };
798*946379e7Schristos 
799*946379e7Schristos /* Initialize a 'struct mixed_string_buffer' to empty.  */
800*946379e7Schristos static inline void
init_mixed_string_buffer(struct mixed_string_buffer * bp)801*946379e7Schristos init_mixed_string_buffer (struct mixed_string_buffer *bp)
802*946379e7Schristos {
803*946379e7Schristos   bp->utf8_buffer = NULL;
804*946379e7Schristos   bp->utf8_buflen = 0;
805*946379e7Schristos   bp->utf8_allocated = 0;
806*946379e7Schristos   bp->utf16_surr = 0;
807*946379e7Schristos   bp->curr_buffer = NULL;
808*946379e7Schristos   bp->curr_buflen = 0;
809*946379e7Schristos   bp->curr_allocated = 0;
810*946379e7Schristos }
811*946379e7Schristos 
812*946379e7Schristos /* Auxiliary function: Append a byte to bp->curr.  */
813*946379e7Schristos static inline void
mixed_string_buffer_append_byte(struct mixed_string_buffer * bp,unsigned char c)814*946379e7Schristos mixed_string_buffer_append_byte (struct mixed_string_buffer *bp, unsigned char c)
815*946379e7Schristos {
816*946379e7Schristos   if (bp->curr_buflen == bp->curr_allocated)
817*946379e7Schristos     {
818*946379e7Schristos       bp->curr_allocated = 2 * bp->curr_allocated + 10;
819*946379e7Schristos       bp->curr_buffer = xrealloc (bp->curr_buffer, bp->curr_allocated);
820*946379e7Schristos     }
821*946379e7Schristos   bp->curr_buffer[bp->curr_buflen++] = c;
822*946379e7Schristos }
823*946379e7Schristos 
824*946379e7Schristos /* Auxiliary function: Ensure count more bytes are available in bp->utf8.  */
825*946379e7Schristos static inline void
mixed_string_buffer_append_unicode_grow(struct mixed_string_buffer * bp,size_t count)826*946379e7Schristos mixed_string_buffer_append_unicode_grow (struct mixed_string_buffer *bp, size_t count)
827*946379e7Schristos {
828*946379e7Schristos   if (bp->utf8_buflen + count > bp->utf8_allocated)
829*946379e7Schristos     {
830*946379e7Schristos       size_t new_allocated = 2 * bp->utf8_allocated + 10;
831*946379e7Schristos       if (new_allocated < bp->utf8_buflen + count)
832*946379e7Schristos 	new_allocated = bp->utf8_buflen + count;
833*946379e7Schristos       bp->utf8_allocated = new_allocated;
834*946379e7Schristos       bp->utf8_buffer = xrealloc (bp->utf8_buffer, new_allocated);
835*946379e7Schristos     }
836*946379e7Schristos }
837*946379e7Schristos 
838*946379e7Schristos /* Auxiliary function: Append a Unicode character to bp->utf8.
839*946379e7Schristos    uc must be < 0x110000.  */
840*946379e7Schristos static inline void
mixed_string_buffer_append_unicode(struct mixed_string_buffer * bp,unsigned int uc)841*946379e7Schristos mixed_string_buffer_append_unicode (struct mixed_string_buffer *bp, unsigned int uc)
842*946379e7Schristos {
843*946379e7Schristos   unsigned char utf8buf[6];
844*946379e7Schristos   int count = u8_uctomb (utf8buf, uc, 6);
845*946379e7Schristos 
846*946379e7Schristos   if (count < 0)
847*946379e7Schristos     /* The caller should have ensured that uc is not out-of-range.  */
848*946379e7Schristos     abort ();
849*946379e7Schristos 
850*946379e7Schristos   mixed_string_buffer_append_unicode_grow (bp, count);
851*946379e7Schristos   memcpy (bp->utf8_buffer + bp->utf8_buflen, utf8buf, count);
852*946379e7Schristos   bp->utf8_buflen += count;
853*946379e7Schristos }
854*946379e7Schristos 
855*946379e7Schristos /* Auxiliary function: Flush bp->utf16_surr into bp->utf8_buffer.  */
856*946379e7Schristos static inline void
mixed_string_buffer_flush_utf16_surr(struct mixed_string_buffer * bp)857*946379e7Schristos mixed_string_buffer_flush_utf16_surr (struct mixed_string_buffer *bp)
858*946379e7Schristos {
859*946379e7Schristos   if (bp->utf16_surr != 0)
860*946379e7Schristos     {
861*946379e7Schristos       /* A half surrogate is invalid, therefore use U+FFFD instead.  */
862*946379e7Schristos       mixed_string_buffer_append_unicode (bp, 0xfffd);
863*946379e7Schristos       bp->utf16_surr = 0;
864*946379e7Schristos     }
865*946379e7Schristos }
866*946379e7Schristos 
867*946379e7Schristos /* Auxiliary function: Flush bp->curr_buffer into bp->utf8_buffer.  */
868*946379e7Schristos static inline void
mixed_string_buffer_flush_curr_buffer(struct mixed_string_buffer * bp,int lineno)869*946379e7Schristos mixed_string_buffer_flush_curr_buffer (struct mixed_string_buffer *bp, int lineno)
870*946379e7Schristos {
871*946379e7Schristos   if (bp->curr_buflen > 0)
872*946379e7Schristos     {
873*946379e7Schristos       char *curr;
874*946379e7Schristos       size_t count;
875*946379e7Schristos 
876*946379e7Schristos       mixed_string_buffer_append_byte (bp, '\0');
877*946379e7Schristos 
878*946379e7Schristos       /* Convert from the source encoding to UTF-8.  */
879*946379e7Schristos       curr = from_current_source_encoding (bp->curr_buffer,
880*946379e7Schristos 					   logical_file_name, lineno);
881*946379e7Schristos 
882*946379e7Schristos       /* Append it to bp->utf8_buffer.  */
883*946379e7Schristos       count = strlen (curr);
884*946379e7Schristos       mixed_string_buffer_append_unicode_grow (bp, count);
885*946379e7Schristos       memcpy (bp->utf8_buffer + bp->utf8_buflen, curr, count);
886*946379e7Schristos       bp->utf8_buflen += count;
887*946379e7Schristos 
888*946379e7Schristos       if (curr != bp->curr_buffer)
889*946379e7Schristos 	free (curr);
890*946379e7Schristos       bp->curr_buflen = 0;
891*946379e7Schristos     }
892*946379e7Schristos }
893*946379e7Schristos 
894*946379e7Schristos /* Append a character or Unicode character to a 'struct mixed_string_buffer'.  */
895*946379e7Schristos static void
mixed_string_buffer_append(struct mixed_string_buffer * bp,int c)896*946379e7Schristos mixed_string_buffer_append (struct mixed_string_buffer *bp, int c)
897*946379e7Schristos {
898*946379e7Schristos   if (IS_UNICODE (c))
899*946379e7Schristos     {
900*946379e7Schristos       /* Append a Unicode character.  */
901*946379e7Schristos 
902*946379e7Schristos       /* Switch from multibyte character mode to Unicode character mode.  */
903*946379e7Schristos       mixed_string_buffer_flush_curr_buffer (bp, line_number);
904*946379e7Schristos 
905*946379e7Schristos       /* Test whether this character and the previous one form a Unicode
906*946379e7Schristos 	 surrogate character pair.  */
907*946379e7Schristos       if (bp->utf16_surr != 0
908*946379e7Schristos 	  && (c >= UNICODE (0xdc00) && c < UNICODE (0xe000)))
909*946379e7Schristos 	{
910*946379e7Schristos 	  unsigned short utf16buf[2];
911*946379e7Schristos 	  unsigned int uc;
912*946379e7Schristos 
913*946379e7Schristos 	  utf16buf[0] = bp->utf16_surr;
914*946379e7Schristos 	  utf16buf[1] = UNICODE_VALUE (c);
915*946379e7Schristos 	  if (u16_mbtouc_aux (&uc, utf16buf, 2) != 2)
916*946379e7Schristos 	    abort ();
917*946379e7Schristos 
918*946379e7Schristos 	  mixed_string_buffer_append_unicode (bp, uc);
919*946379e7Schristos 	  bp->utf16_surr = 0;
920*946379e7Schristos 	}
921*946379e7Schristos       else
922*946379e7Schristos 	{
923*946379e7Schristos 	  mixed_string_buffer_flush_utf16_surr (bp);
924*946379e7Schristos 
925*946379e7Schristos 	  if (c >= UNICODE (0xd800) && c < UNICODE (0xdc00))
926*946379e7Schristos 	    bp->utf16_surr = UNICODE_VALUE (c);
927*946379e7Schristos 	  else
928*946379e7Schristos 	    mixed_string_buffer_append_unicode (bp, UNICODE_VALUE (c));
929*946379e7Schristos 	}
930*946379e7Schristos     }
931*946379e7Schristos   else
932*946379e7Schristos     {
933*946379e7Schristos       /* Append a single byte.  */
934*946379e7Schristos 
935*946379e7Schristos       /* Switch from Unicode character mode to multibyte character mode.  */
936*946379e7Schristos       mixed_string_buffer_flush_utf16_surr (bp);
937*946379e7Schristos 
938*946379e7Schristos       /* When a newline is seen, convert the accumulated multibyte sequence.
939*946379e7Schristos 	 This ensures a correct line number in the error message in case of
940*946379e7Schristos 	 a conversion error.  The "- 1" is to account for the newline.  */
941*946379e7Schristos       if (c == '\n')
942*946379e7Schristos 	mixed_string_buffer_flush_curr_buffer (bp, line_number - 1);
943*946379e7Schristos 
944*946379e7Schristos       mixed_string_buffer_append_byte (bp, (unsigned char) c);
945*946379e7Schristos     }
946*946379e7Schristos }
947*946379e7Schristos 
948*946379e7Schristos /* Return the string buffer's contents.  */
949*946379e7Schristos static char *
mixed_string_buffer_result(struct mixed_string_buffer * bp)950*946379e7Schristos mixed_string_buffer_result (struct mixed_string_buffer *bp)
951*946379e7Schristos {
952*946379e7Schristos   /* Flush all into bp->utf8_buffer.  */
953*946379e7Schristos   mixed_string_buffer_flush_utf16_surr (bp);
954*946379e7Schristos   mixed_string_buffer_flush_curr_buffer (bp, line_number);
955*946379e7Schristos   /* NUL-terminate it.  */
956*946379e7Schristos   mixed_string_buffer_append_unicode_grow (bp, 1);
957*946379e7Schristos   bp->utf8_buffer[bp->utf8_buflen] = '\0';
958*946379e7Schristos   /* Return it.  */
959*946379e7Schristos   return bp->utf8_buffer;
960*946379e7Schristos }
961*946379e7Schristos 
962*946379e7Schristos /* Free the memory pointed to by a 'struct mixed_string_buffer'.  */
963*946379e7Schristos static inline void
free_mixed_string_buffer(struct mixed_string_buffer * bp)964*946379e7Schristos free_mixed_string_buffer (struct mixed_string_buffer *bp)
965*946379e7Schristos {
966*946379e7Schristos   free (bp->utf8_buffer);
967*946379e7Schristos   free (bp->curr_buffer);
968*946379e7Schristos }
969*946379e7Schristos 
970*946379e7Schristos 
971*946379e7Schristos /* ========================== Reading of tokens.  ========================== */
972*946379e7Schristos 
973*946379e7Schristos 
974*946379e7Schristos enum token_type_ty
975*946379e7Schristos {
976*946379e7Schristos   token_type_eof,
977*946379e7Schristos   token_type_lparen,		/* ( */
978*946379e7Schristos   token_type_rparen,		/* ) */
979*946379e7Schristos   token_type_comma,		/* , */
980*946379e7Schristos   token_type_string,		/* "abc", 'abc', """abc""", '''abc''' */
981*946379e7Schristos   token_type_symbol,		/* symbol, number */
982*946379e7Schristos   token_type_other		/* misc. operator */
983*946379e7Schristos };
984*946379e7Schristos typedef enum token_type_ty token_type_ty;
985*946379e7Schristos 
986*946379e7Schristos typedef struct token_ty token_ty;
987*946379e7Schristos struct token_ty
988*946379e7Schristos {
989*946379e7Schristos   token_type_ty type;
990*946379e7Schristos   char *string;		/* for token_type_string, token_type_symbol */
991*946379e7Schristos   refcounted_string_list_ty *comment;	/* for token_type_string */
992*946379e7Schristos   int line_number;
993*946379e7Schristos };
994*946379e7Schristos 
995*946379e7Schristos 
996*946379e7Schristos /* There are two different input syntaxes for strings, "abc" and r"abc",
997*946379e7Schristos    and two different input syntaxes for Unicode strings, u"abc" and ur"abc".
998*946379e7Schristos    Which escape sequences are understood, i.e. what is interpreted specially
999*946379e7Schristos    after backslash?
1000*946379e7Schristos     "abc"     \<nl> \\ \' \" \a\b\f\n\r\t\v \ooo \xnn
1001*946379e7Schristos     r"abc"
1002*946379e7Schristos     u"abc"    \<nl> \\ \' \" \a\b\f\n\r\t\v \ooo \xnn \unnnn \Unnnnnnnn \N{...}
1003*946379e7Schristos     ur"abc"                                           \unnnn
1004*946379e7Schristos    The \unnnn values are UTF-16 values; a single \Unnnnnnnn can expand to two
1005*946379e7Schristos    \unnnn items.  The \ooo and \xnn values are in the current source encoding.
1006*946379e7Schristos  */
1007*946379e7Schristos 
1008*946379e7Schristos static int
phase7_getuc(int quote_char,bool triple,bool interpret_ansic,bool interpret_unicode,unsigned int * backslash_counter)1009*946379e7Schristos phase7_getuc (int quote_char,
1010*946379e7Schristos 	      bool triple, bool interpret_ansic, bool interpret_unicode,
1011*946379e7Schristos 	      unsigned int *backslash_counter)
1012*946379e7Schristos {
1013*946379e7Schristos   int c;
1014*946379e7Schristos 
1015*946379e7Schristos   for (;;)
1016*946379e7Schristos     {
1017*946379e7Schristos       /* Use phase 2, because phase 3 elides comments.  */
1018*946379e7Schristos       c = phase2_getc ();
1019*946379e7Schristos 
1020*946379e7Schristos       if (c == UEOF)
1021*946379e7Schristos 	return P7_EOF;
1022*946379e7Schristos 
1023*946379e7Schristos       if (c == quote_char && (interpret_ansic || (*backslash_counter & 1) == 0))
1024*946379e7Schristos 	{
1025*946379e7Schristos 	  if (triple)
1026*946379e7Schristos 	    {
1027*946379e7Schristos 	      int c1 = phase2_getc ();
1028*946379e7Schristos 	      if (c1 == quote_char)
1029*946379e7Schristos 		{
1030*946379e7Schristos 		  int c2 = phase2_getc ();
1031*946379e7Schristos 		  if (c2 == quote_char)
1032*946379e7Schristos 		    return P7_STRING_END;
1033*946379e7Schristos 		  phase2_ungetc (c2);
1034*946379e7Schristos 		}
1035*946379e7Schristos 	      phase2_ungetc (c1);
1036*946379e7Schristos 	      return UNICODE (c);
1037*946379e7Schristos 	    }
1038*946379e7Schristos 	  else
1039*946379e7Schristos 	    return P7_STRING_END;
1040*946379e7Schristos 	}
1041*946379e7Schristos 
1042*946379e7Schristos       if (c == '\n')
1043*946379e7Schristos 	{
1044*946379e7Schristos 	  if (triple)
1045*946379e7Schristos 	    {
1046*946379e7Schristos 	      *backslash_counter = 0;
1047*946379e7Schristos 	      return UNICODE ('\n');
1048*946379e7Schristos 	    }
1049*946379e7Schristos 	  /* In r"..." and ur"..." strings, newline is only allowed
1050*946379e7Schristos 	     immediately after an odd number of backslashes (although the
1051*946379e7Schristos 	     backslashes are not interpreted!).  */
1052*946379e7Schristos 	  if (!(interpret_ansic || (*backslash_counter & 1) == 0))
1053*946379e7Schristos 	    {
1054*946379e7Schristos 	      *backslash_counter = 0;
1055*946379e7Schristos 	      return UNICODE ('\n');
1056*946379e7Schristos 	    }
1057*946379e7Schristos 	  phase2_ungetc (c);
1058*946379e7Schristos 	  error_with_progname = false;
1059*946379e7Schristos 	  error (0, 0, _("%s:%d: warning: unterminated string"),
1060*946379e7Schristos 		 logical_file_name, line_number);
1061*946379e7Schristos 	  error_with_progname = true;
1062*946379e7Schristos 	  return P7_STRING_END;
1063*946379e7Schristos 	}
1064*946379e7Schristos 
1065*946379e7Schristos       if (c != '\\')
1066*946379e7Schristos 	{
1067*946379e7Schristos 	  *backslash_counter = 0;
1068*946379e7Schristos 	  return UNICODE (c);
1069*946379e7Schristos 	}
1070*946379e7Schristos 
1071*946379e7Schristos       /* Backslash handling.  */
1072*946379e7Schristos 
1073*946379e7Schristos       if (!interpret_ansic && !interpret_unicode)
1074*946379e7Schristos 	{
1075*946379e7Schristos 	  ++*backslash_counter;
1076*946379e7Schristos 	  return UNICODE ('\\');
1077*946379e7Schristos 	}
1078*946379e7Schristos 
1079*946379e7Schristos       /* Dispatch according to the character following the backslash.  */
1080*946379e7Schristos       c = phase2_getc ();
1081*946379e7Schristos       if (c == UEOF)
1082*946379e7Schristos 	{
1083*946379e7Schristos 	  ++*backslash_counter;
1084*946379e7Schristos 	  return UNICODE ('\\');
1085*946379e7Schristos 	}
1086*946379e7Schristos 
1087*946379e7Schristos       if (interpret_ansic)
1088*946379e7Schristos 	switch (c)
1089*946379e7Schristos 	  {
1090*946379e7Schristos 	  case '\n':
1091*946379e7Schristos 	    continue;
1092*946379e7Schristos 	  case '\\':
1093*946379e7Schristos 	    ++*backslash_counter;
1094*946379e7Schristos 	    return UNICODE (c);
1095*946379e7Schristos 	  case '\'': case '"':
1096*946379e7Schristos 	    *backslash_counter = 0;
1097*946379e7Schristos 	    return UNICODE (c);
1098*946379e7Schristos 	  case 'a':
1099*946379e7Schristos 	    *backslash_counter = 0;
1100*946379e7Schristos 	    return UNICODE ('\a');
1101*946379e7Schristos 	  case 'b':
1102*946379e7Schristos 	    *backslash_counter = 0;
1103*946379e7Schristos 	    return UNICODE ('\b');
1104*946379e7Schristos 	  case 'f':
1105*946379e7Schristos 	    *backslash_counter = 0;
1106*946379e7Schristos 	    return UNICODE ('\f');
1107*946379e7Schristos 	  case 'n':
1108*946379e7Schristos 	    *backslash_counter = 0;
1109*946379e7Schristos 	    return UNICODE ('\n');
1110*946379e7Schristos 	  case 'r':
1111*946379e7Schristos 	    *backslash_counter = 0;
1112*946379e7Schristos 	    return UNICODE ('\r');
1113*946379e7Schristos 	  case 't':
1114*946379e7Schristos 	    *backslash_counter = 0;
1115*946379e7Schristos 	    return UNICODE ('\t');
1116*946379e7Schristos 	  case 'v':
1117*946379e7Schristos 	    *backslash_counter = 0;
1118*946379e7Schristos 	    return UNICODE ('\v');
1119*946379e7Schristos 	  case '0': case '1': case '2': case '3': case '4':
1120*946379e7Schristos 	  case '5': case '6': case '7':
1121*946379e7Schristos 	    {
1122*946379e7Schristos 	      int n = c - '0';
1123*946379e7Schristos 
1124*946379e7Schristos 	      c = phase2_getc ();
1125*946379e7Schristos 	      if (c != UEOF)
1126*946379e7Schristos 		{
1127*946379e7Schristos 		  if (c >= '0' && c <= '7')
1128*946379e7Schristos 		    {
1129*946379e7Schristos 		      n = (n << 3) + (c - '0');
1130*946379e7Schristos 		      c = phase2_getc ();
1131*946379e7Schristos 		      if (c != UEOF)
1132*946379e7Schristos 			{
1133*946379e7Schristos 			  if (c >= '0' && c <= '7')
1134*946379e7Schristos 			    n = (n << 3) + (c - '0');
1135*946379e7Schristos 			  else
1136*946379e7Schristos 			    phase2_ungetc (c);
1137*946379e7Schristos 			}
1138*946379e7Schristos 		    }
1139*946379e7Schristos 		  else
1140*946379e7Schristos 		    phase2_ungetc (c);
1141*946379e7Schristos 		}
1142*946379e7Schristos 	      *backslash_counter = 0;
1143*946379e7Schristos 	      return (unsigned char) n;
1144*946379e7Schristos 	    }
1145*946379e7Schristos 	  case 'x':
1146*946379e7Schristos 	    {
1147*946379e7Schristos 	      int c1 = phase2_getc ();
1148*946379e7Schristos 	      int n1;
1149*946379e7Schristos 
1150*946379e7Schristos 	      if (c1 >= '0' && c1 <= '9')
1151*946379e7Schristos 		n1 = c1 - '0';
1152*946379e7Schristos 	      else if (c1 >= 'A' && c1 <= 'F')
1153*946379e7Schristos 		n1 = c1 - 'A' + 10;
1154*946379e7Schristos 	      else if (c1 >= 'a' && c1 <= 'f')
1155*946379e7Schristos 		n1 = c1 - 'a' + 10;
1156*946379e7Schristos 	      else
1157*946379e7Schristos 		n1 = -1;
1158*946379e7Schristos 
1159*946379e7Schristos 	      if (n1 >= 0)
1160*946379e7Schristos 		{
1161*946379e7Schristos 		  int c2 = phase2_getc ();
1162*946379e7Schristos 		  int n2;
1163*946379e7Schristos 
1164*946379e7Schristos 		  if (c2 >= '0' && c2 <= '9')
1165*946379e7Schristos 		    n2 = c2 - '0';
1166*946379e7Schristos 		  else if (c2 >= 'A' && c2 <= 'F')
1167*946379e7Schristos 		    n2 = c2 - 'A' + 10;
1168*946379e7Schristos 		  else if (c2 >= 'a' && c2 <= 'f')
1169*946379e7Schristos 		    n2 = c2 - 'a' + 10;
1170*946379e7Schristos 		  else
1171*946379e7Schristos 		    n2 = -1;
1172*946379e7Schristos 
1173*946379e7Schristos 		  if (n2 >= 0)
1174*946379e7Schristos 		    {
1175*946379e7Schristos 		      *backslash_counter = 0;
1176*946379e7Schristos 		      return (unsigned char) ((n1 << 4) + n2);
1177*946379e7Schristos 		    }
1178*946379e7Schristos 
1179*946379e7Schristos 		  phase2_ungetc (c2);
1180*946379e7Schristos 		}
1181*946379e7Schristos 	      phase2_ungetc (c1);
1182*946379e7Schristos 	      phase2_ungetc (c);
1183*946379e7Schristos 	      ++*backslash_counter;
1184*946379e7Schristos 	      return UNICODE ('\\');
1185*946379e7Schristos 	    }
1186*946379e7Schristos 	  }
1187*946379e7Schristos 
1188*946379e7Schristos       if (interpret_unicode)
1189*946379e7Schristos 	{
1190*946379e7Schristos 	  if (c == 'u')
1191*946379e7Schristos 	    {
1192*946379e7Schristos 	      unsigned char buf[4];
1193*946379e7Schristos 	      unsigned int n = 0;
1194*946379e7Schristos 	      int i;
1195*946379e7Schristos 
1196*946379e7Schristos 	      for (i = 0; i < 4; i++)
1197*946379e7Schristos 		{
1198*946379e7Schristos 		  int c1 = phase2_getc ();
1199*946379e7Schristos 
1200*946379e7Schristos 		  if (c1 >= '0' && c1 <= '9')
1201*946379e7Schristos 		    n = (n << 4) + (c1 - '0');
1202*946379e7Schristos 		  else if (c1 >= 'A' && c1 <= 'F')
1203*946379e7Schristos 		    n = (n << 4) + (c1 - 'A' + 10);
1204*946379e7Schristos 		  else if (c1 >= 'a' && c1 <= 'f')
1205*946379e7Schristos 		    n = (n << 4) + (c1 - 'a' + 10);
1206*946379e7Schristos 		  else
1207*946379e7Schristos 		    {
1208*946379e7Schristos 		      phase2_ungetc (c1);
1209*946379e7Schristos 		      while (--i >= 0)
1210*946379e7Schristos 			phase2_ungetc (buf[i]);
1211*946379e7Schristos 		      phase2_ungetc (c);
1212*946379e7Schristos 		      ++*backslash_counter;
1213*946379e7Schristos 		      return UNICODE ('\\');
1214*946379e7Schristos 		    }
1215*946379e7Schristos 
1216*946379e7Schristos 		  buf[i] = c1;
1217*946379e7Schristos 		}
1218*946379e7Schristos 	      *backslash_counter = 0;
1219*946379e7Schristos 	      return UNICODE (n);
1220*946379e7Schristos 	    }
1221*946379e7Schristos 
1222*946379e7Schristos 	  if (interpret_ansic)
1223*946379e7Schristos 	    {
1224*946379e7Schristos 	      if (c == 'U')
1225*946379e7Schristos 		{
1226*946379e7Schristos 		  unsigned char buf[8];
1227*946379e7Schristos 		  unsigned int n = 0;
1228*946379e7Schristos 		  int i;
1229*946379e7Schristos 
1230*946379e7Schristos 		  for (i = 0; i < 8; i++)
1231*946379e7Schristos 		    {
1232*946379e7Schristos 		      int c1 = phase2_getc ();
1233*946379e7Schristos 
1234*946379e7Schristos 		      if (c1 >= '0' && c1 <= '9')
1235*946379e7Schristos 			n = (n << 4) + (c1 - '0');
1236*946379e7Schristos 		      else if (c1 >= 'A' && c1 <= 'F')
1237*946379e7Schristos 			n = (n << 4) + (c1 - 'A' + 10);
1238*946379e7Schristos 		      else if (c1 >= 'a' && c1 <= 'f')
1239*946379e7Schristos 			n = (n << 4) + (c1 - 'a' + 10);
1240*946379e7Schristos 		      else
1241*946379e7Schristos 			{
1242*946379e7Schristos 			  phase2_ungetc (c1);
1243*946379e7Schristos 			  while (--i >= 0)
1244*946379e7Schristos 			    phase2_ungetc (buf[i]);
1245*946379e7Schristos 			  phase2_ungetc (c);
1246*946379e7Schristos 			  ++*backslash_counter;
1247*946379e7Schristos 			  return UNICODE ('\\');
1248*946379e7Schristos 			}
1249*946379e7Schristos 
1250*946379e7Schristos 		      buf[i] = c1;
1251*946379e7Schristos 		    }
1252*946379e7Schristos 		  if (n < 0x110000)
1253*946379e7Schristos 		    {
1254*946379e7Schristos 		      *backslash_counter = 0;
1255*946379e7Schristos 		      return UNICODE (n);
1256*946379e7Schristos 		    }
1257*946379e7Schristos 
1258*946379e7Schristos 		  error_with_progname = false;
1259*946379e7Schristos 		  error (0, 0, _("%s:%d: warning: invalid Unicode character"),
1260*946379e7Schristos 			 logical_file_name, line_number);
1261*946379e7Schristos 		  error_with_progname = true;
1262*946379e7Schristos 
1263*946379e7Schristos 		  while (--i >= 0)
1264*946379e7Schristos 		    phase2_ungetc (buf[i]);
1265*946379e7Schristos 		  phase2_ungetc (c);
1266*946379e7Schristos 		  ++*backslash_counter;
1267*946379e7Schristos 		  return UNICODE ('\\');
1268*946379e7Schristos 		}
1269*946379e7Schristos 
1270*946379e7Schristos 	      if (c == 'N')
1271*946379e7Schristos 		{
1272*946379e7Schristos 		  int c1 = phase2_getc ();
1273*946379e7Schristos 		  if (c1 == '{')
1274*946379e7Schristos 		    {
1275*946379e7Schristos 		      unsigned char buf[UNINAME_MAX + 1];
1276*946379e7Schristos 		      int i;
1277*946379e7Schristos 		      unsigned int n;
1278*946379e7Schristos 
1279*946379e7Schristos 		      for (i = 0; i < UNINAME_MAX; i++)
1280*946379e7Schristos 			{
1281*946379e7Schristos 			  int c2 = phase2_getc ();
1282*946379e7Schristos 			  if (!(c2 >= ' ' && c2 <= '~'))
1283*946379e7Schristos 			    {
1284*946379e7Schristos 			      phase2_ungetc (c2);
1285*946379e7Schristos 			      while (--i >= 0)
1286*946379e7Schristos 				phase2_ungetc (buf[i]);
1287*946379e7Schristos 			      phase2_ungetc (c1);
1288*946379e7Schristos 			      phase2_ungetc (c);
1289*946379e7Schristos 			      ++*backslash_counter;
1290*946379e7Schristos 			      return UNICODE ('\\');
1291*946379e7Schristos 			    }
1292*946379e7Schristos 			  if (c2 == '}')
1293*946379e7Schristos 			    break;
1294*946379e7Schristos 			  buf[i] = c2;
1295*946379e7Schristos 			}
1296*946379e7Schristos 		      buf[i] = '\0';
1297*946379e7Schristos 
1298*946379e7Schristos 		      n = unicode_name_character ((char *) buf);
1299*946379e7Schristos 		      if (n != UNINAME_INVALID)
1300*946379e7Schristos 			{
1301*946379e7Schristos 			  *backslash_counter = 0;
1302*946379e7Schristos 			  return UNICODE (n);
1303*946379e7Schristos 			}
1304*946379e7Schristos 
1305*946379e7Schristos 		      phase2_ungetc ('}');
1306*946379e7Schristos 		      while (--i >= 0)
1307*946379e7Schristos 			phase2_ungetc (buf[i]);
1308*946379e7Schristos 		    }
1309*946379e7Schristos 		  phase2_ungetc (c1);
1310*946379e7Schristos 		  phase2_ungetc (c);
1311*946379e7Schristos 		  ++*backslash_counter;
1312*946379e7Schristos 		  return UNICODE ('\\');
1313*946379e7Schristos 		}
1314*946379e7Schristos 	    }
1315*946379e7Schristos 	}
1316*946379e7Schristos 
1317*946379e7Schristos       phase2_ungetc (c);
1318*946379e7Schristos       ++*backslash_counter;
1319*946379e7Schristos       return UNICODE ('\\');
1320*946379e7Schristos     }
1321*946379e7Schristos }
1322*946379e7Schristos 
1323*946379e7Schristos 
1324*946379e7Schristos /* Combine characters into tokens.  Discard whitespace except newlines at
1325*946379e7Schristos    the end of logical lines.  */
1326*946379e7Schristos 
1327*946379e7Schristos /* Number of pending open parentheses/braces/brackets.  */
1328*946379e7Schristos static int open_pbb;
1329*946379e7Schristos 
1330*946379e7Schristos static token_ty phase5_pushback[1];
1331*946379e7Schristos static int phase5_pushback_length;
1332*946379e7Schristos 
1333*946379e7Schristos static void
phase5_get(token_ty * tp)1334*946379e7Schristos phase5_get (token_ty *tp)
1335*946379e7Schristos {
1336*946379e7Schristos   int c;
1337*946379e7Schristos 
1338*946379e7Schristos   if (phase5_pushback_length)
1339*946379e7Schristos     {
1340*946379e7Schristos       *tp = phase5_pushback[--phase5_pushback_length];
1341*946379e7Schristos       return;
1342*946379e7Schristos     }
1343*946379e7Schristos 
1344*946379e7Schristos   for (;;)
1345*946379e7Schristos     {
1346*946379e7Schristos       tp->line_number = line_number;
1347*946379e7Schristos       c = phase3_getc ();
1348*946379e7Schristos 
1349*946379e7Schristos       switch (c)
1350*946379e7Schristos 	{
1351*946379e7Schristos 	case UEOF:
1352*946379e7Schristos 	  tp->type = token_type_eof;
1353*946379e7Schristos 	  return;
1354*946379e7Schristos 
1355*946379e7Schristos 	case ' ':
1356*946379e7Schristos 	case '\t':
1357*946379e7Schristos 	case '\f':
1358*946379e7Schristos 	  /* Ignore whitespace and comments.  */
1359*946379e7Schristos 	  continue;
1360*946379e7Schristos 
1361*946379e7Schristos 	case '\n':
1362*946379e7Schristos 	  if (last_non_comment_line > last_comment_line)
1363*946379e7Schristos 	    savable_comment_reset ();
1364*946379e7Schristos 	  /* Ignore newline if and only if it is used for implicit line
1365*946379e7Schristos 	     joining.  */
1366*946379e7Schristos 	  if (open_pbb > 0)
1367*946379e7Schristos 	    continue;
1368*946379e7Schristos 	  tp->type = token_type_other;
1369*946379e7Schristos 	  return;
1370*946379e7Schristos 	}
1371*946379e7Schristos 
1372*946379e7Schristos       last_non_comment_line = tp->line_number;
1373*946379e7Schristos 
1374*946379e7Schristos       switch (c)
1375*946379e7Schristos 	{
1376*946379e7Schristos 	case '.':
1377*946379e7Schristos 	  {
1378*946379e7Schristos 	    int c1 = phase3_getc ();
1379*946379e7Schristos 	    phase3_ungetc (c1);
1380*946379e7Schristos 	    if (!(c1 >= '0' && c1 <= '9'))
1381*946379e7Schristos 	      {
1382*946379e7Schristos 
1383*946379e7Schristos 		tp->type = token_type_other;
1384*946379e7Schristos 		return;
1385*946379e7Schristos 	      }
1386*946379e7Schristos 	  }
1387*946379e7Schristos 	  /* FALLTHROUGH */
1388*946379e7Schristos 	case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
1389*946379e7Schristos 	case 'G': case 'H': case 'I': case 'J': case 'K': case 'L':
1390*946379e7Schristos 	case 'M': case 'N': case 'O': case 'P': case 'Q':
1391*946379e7Schristos 	case 'S': case 'T':           case 'V': case 'W': case 'X':
1392*946379e7Schristos 	case 'Y': case 'Z':
1393*946379e7Schristos 	case '_':
1394*946379e7Schristos 	case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
1395*946379e7Schristos 	case 'g': case 'h': case 'i': case 'j': case 'k': case 'l':
1396*946379e7Schristos 	case 'm': case 'n': case 'o': case 'p': case 'q':
1397*946379e7Schristos 	case 's': case 't':           case 'v': case 'w': case 'x':
1398*946379e7Schristos 	case 'y': case 'z':
1399*946379e7Schristos 	case '0': case '1': case '2': case '3': case '4':
1400*946379e7Schristos 	case '5': case '6': case '7': case '8': case '9':
1401*946379e7Schristos 	symbol:
1402*946379e7Schristos 	  /* Symbol, or part of a number.  */
1403*946379e7Schristos 	  {
1404*946379e7Schristos 	    static char *buffer;
1405*946379e7Schristos 	    static int bufmax;
1406*946379e7Schristos 	    int bufpos;
1407*946379e7Schristos 
1408*946379e7Schristos 	    bufpos = 0;
1409*946379e7Schristos 	    for (;;)
1410*946379e7Schristos 	      {
1411*946379e7Schristos 		if (bufpos >= bufmax)
1412*946379e7Schristos 		  {
1413*946379e7Schristos 		    bufmax = 2 * bufmax + 10;
1414*946379e7Schristos 		    buffer = xrealloc (buffer, bufmax);
1415*946379e7Schristos 		  }
1416*946379e7Schristos 		buffer[bufpos++] = c;
1417*946379e7Schristos 		c = phase3_getc ();
1418*946379e7Schristos 		switch (c)
1419*946379e7Schristos 		  {
1420*946379e7Schristos 		  case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
1421*946379e7Schristos 		  case 'G': case 'H': case 'I': case 'J': case 'K': case 'L':
1422*946379e7Schristos 		  case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R':
1423*946379e7Schristos 		  case 'S': case 'T': case 'U': case 'V': case 'W': case 'X':
1424*946379e7Schristos 		  case 'Y': case 'Z':
1425*946379e7Schristos 		  case '_':
1426*946379e7Schristos 		  case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
1427*946379e7Schristos 		  case 'g': case 'h': case 'i': case 'j': case 'k': case 'l':
1428*946379e7Schristos 		  case 'm': case 'n': case 'o': case 'p': case 'q': case 'r':
1429*946379e7Schristos 		  case 's': case 't': case 'u': case 'v': case 'w': case 'x':
1430*946379e7Schristos 		  case 'y': case 'z':
1431*946379e7Schristos 		  case '0': case '1': case '2': case '3': case '4':
1432*946379e7Schristos 		  case '5': case '6': case '7': case '8': case '9':
1433*946379e7Schristos 		    continue;
1434*946379e7Schristos 		  default:
1435*946379e7Schristos 		    phase3_ungetc (c);
1436*946379e7Schristos 		    break;
1437*946379e7Schristos 		  }
1438*946379e7Schristos 		break;
1439*946379e7Schristos 	      }
1440*946379e7Schristos 	    if (bufpos >= bufmax)
1441*946379e7Schristos 	      {
1442*946379e7Schristos 		bufmax = 2 * bufmax + 10;
1443*946379e7Schristos 		buffer = xrealloc (buffer, bufmax);
1444*946379e7Schristos 	      }
1445*946379e7Schristos 	    buffer[bufpos] = '\0';
1446*946379e7Schristos 	    tp->string = xstrdup (buffer);
1447*946379e7Schristos 	    tp->type = token_type_symbol;
1448*946379e7Schristos 	    return;
1449*946379e7Schristos 	  }
1450*946379e7Schristos 
1451*946379e7Schristos 	/* Strings.  */
1452*946379e7Schristos 	  {
1453*946379e7Schristos 	    struct mixed_string_buffer literal;
1454*946379e7Schristos 	    int quote_char;
1455*946379e7Schristos 	    bool interpret_ansic;
1456*946379e7Schristos 	    bool interpret_unicode;
1457*946379e7Schristos 	    bool triple;
1458*946379e7Schristos 	    unsigned int backslash_counter;
1459*946379e7Schristos 
1460*946379e7Schristos 	    case 'R': case 'r':
1461*946379e7Schristos 	      {
1462*946379e7Schristos 		int c1 = phase2_getc ();
1463*946379e7Schristos 		if (c1 == '"' || c1 == '\'')
1464*946379e7Schristos 		  {
1465*946379e7Schristos 		    quote_char = c1;
1466*946379e7Schristos 		    interpret_ansic = false;
1467*946379e7Schristos 		    interpret_unicode = false;
1468*946379e7Schristos 		    goto string;
1469*946379e7Schristos 		  }
1470*946379e7Schristos 		phase2_ungetc (c1);
1471*946379e7Schristos 		goto symbol;
1472*946379e7Schristos 	      }
1473*946379e7Schristos 
1474*946379e7Schristos 	    case 'U': case 'u':
1475*946379e7Schristos 	      {
1476*946379e7Schristos 		int c1 = phase2_getc ();
1477*946379e7Schristos 		if (c1 == '"' || c1 == '\'')
1478*946379e7Schristos 		  {
1479*946379e7Schristos 		    quote_char = c1;
1480*946379e7Schristos 		    interpret_ansic = true;
1481*946379e7Schristos 		    interpret_unicode = true;
1482*946379e7Schristos 		    goto string;
1483*946379e7Schristos 		  }
1484*946379e7Schristos 		if (c1 == 'R' || c1 == 'r')
1485*946379e7Schristos 		  {
1486*946379e7Schristos 		    int c2 = phase2_getc ();
1487*946379e7Schristos 		    if (c2 == '"' || c2 == '\'')
1488*946379e7Schristos 		      {
1489*946379e7Schristos 			quote_char = c2;
1490*946379e7Schristos 			interpret_ansic = false;
1491*946379e7Schristos 			interpret_unicode = true;
1492*946379e7Schristos 			goto string;
1493*946379e7Schristos 		      }
1494*946379e7Schristos 		    phase2_ungetc (c2);
1495*946379e7Schristos 		  }
1496*946379e7Schristos 		phase2_ungetc (c1);
1497*946379e7Schristos 		goto symbol;
1498*946379e7Schristos 	      }
1499*946379e7Schristos 
1500*946379e7Schristos 	    case '"': case '\'':
1501*946379e7Schristos 	      quote_char = c;
1502*946379e7Schristos 	      interpret_ansic = true;
1503*946379e7Schristos 	      interpret_unicode = false;
1504*946379e7Schristos 	    string:
1505*946379e7Schristos 	      triple = false;
1506*946379e7Schristos 	      {
1507*946379e7Schristos 		int c1 = phase2_getc ();
1508*946379e7Schristos 		if (c1 == quote_char)
1509*946379e7Schristos 		  {
1510*946379e7Schristos 		    int c2 = phase2_getc ();
1511*946379e7Schristos 		    if (c2 == quote_char)
1512*946379e7Schristos 		      triple = true;
1513*946379e7Schristos 		    else
1514*946379e7Schristos 		      {
1515*946379e7Schristos 			phase2_ungetc (c2);
1516*946379e7Schristos 			phase2_ungetc (c1);
1517*946379e7Schristos 		      }
1518*946379e7Schristos 		  }
1519*946379e7Schristos 		else
1520*946379e7Schristos 		  phase2_ungetc (c1);
1521*946379e7Schristos 	      }
1522*946379e7Schristos 	      backslash_counter = 0;
1523*946379e7Schristos 	      /* Start accumulating the string.  */
1524*946379e7Schristos 	      init_mixed_string_buffer (&literal);
1525*946379e7Schristos 	      for (;;)
1526*946379e7Schristos 		{
1527*946379e7Schristos 		  int uc = phase7_getuc (quote_char, triple, interpret_ansic,
1528*946379e7Schristos 					 interpret_unicode, &backslash_counter);
1529*946379e7Schristos 
1530*946379e7Schristos 		  if (uc == P7_EOF || uc == P7_STRING_END)
1531*946379e7Schristos 		    break;
1532*946379e7Schristos 
1533*946379e7Schristos 		  if (IS_UNICODE (uc))
1534*946379e7Schristos 		    assert (UNICODE_VALUE (uc) >= 0
1535*946379e7Schristos 			    && UNICODE_VALUE (uc) < 0x110000);
1536*946379e7Schristos 
1537*946379e7Schristos 		  mixed_string_buffer_append (&literal, uc);
1538*946379e7Schristos 		}
1539*946379e7Schristos 	      tp->string = xstrdup (mixed_string_buffer_result (&literal));
1540*946379e7Schristos 	      free_mixed_string_buffer (&literal);
1541*946379e7Schristos 	      tp->comment = add_reference (savable_comment);
1542*946379e7Schristos 	      tp->type = token_type_string;
1543*946379e7Schristos 	      return;
1544*946379e7Schristos 	  }
1545*946379e7Schristos 
1546*946379e7Schristos 	case '(':
1547*946379e7Schristos 	  open_pbb++;
1548*946379e7Schristos 	  tp->type = token_type_lparen;
1549*946379e7Schristos 	  return;
1550*946379e7Schristos 
1551*946379e7Schristos 	case ')':
1552*946379e7Schristos 	  if (open_pbb > 0)
1553*946379e7Schristos 	    open_pbb--;
1554*946379e7Schristos 	  tp->type = token_type_rparen;
1555*946379e7Schristos 	  return;
1556*946379e7Schristos 
1557*946379e7Schristos 	case ',':
1558*946379e7Schristos 	  tp->type = token_type_comma;
1559*946379e7Schristos 	  return;
1560*946379e7Schristos 
1561*946379e7Schristos 	case '[': case '{':
1562*946379e7Schristos 	  open_pbb++;
1563*946379e7Schristos 	  tp->type = token_type_other;
1564*946379e7Schristos 	  return;
1565*946379e7Schristos 
1566*946379e7Schristos 	case ']': case '}':
1567*946379e7Schristos 	  if (open_pbb > 0)
1568*946379e7Schristos 	    open_pbb--;
1569*946379e7Schristos 	  tp->type = token_type_other;
1570*946379e7Schristos 	  return;
1571*946379e7Schristos 
1572*946379e7Schristos 	default:
1573*946379e7Schristos 	  /* We could carefully recognize each of the 2 and 3 character
1574*946379e7Schristos 	     operators, but it is not necessary, as we only need to recognize
1575*946379e7Schristos 	     gettext invocations.  Don't bother.  */
1576*946379e7Schristos 	  tp->type = token_type_other;
1577*946379e7Schristos 	  return;
1578*946379e7Schristos 	}
1579*946379e7Schristos     }
1580*946379e7Schristos }
1581*946379e7Schristos 
1582*946379e7Schristos /* Supports only one pushback token.  */
1583*946379e7Schristos static void
phase5_unget(token_ty * tp)1584*946379e7Schristos phase5_unget (token_ty *tp)
1585*946379e7Schristos {
1586*946379e7Schristos   if (tp->type != token_type_eof)
1587*946379e7Schristos     {
1588*946379e7Schristos       if (phase5_pushback_length == SIZEOF (phase5_pushback))
1589*946379e7Schristos 	abort ();
1590*946379e7Schristos       phase5_pushback[phase5_pushback_length++] = *tp;
1591*946379e7Schristos     }
1592*946379e7Schristos }
1593*946379e7Schristos 
1594*946379e7Schristos 
1595*946379e7Schristos /* Combine adjacent strings to form a single string.  Note that the end
1596*946379e7Schristos    of a logical line appears as a token of its own, therefore strings that
1597*946379e7Schristos    belong to different logical lines will not be concatenated.  */
1598*946379e7Schristos 
1599*946379e7Schristos static void
x_python_lex(token_ty * tp)1600*946379e7Schristos x_python_lex (token_ty *tp)
1601*946379e7Schristos {
1602*946379e7Schristos   phase5_get (tp);
1603*946379e7Schristos   if (tp->type != token_type_string)
1604*946379e7Schristos     return;
1605*946379e7Schristos   for (;;)
1606*946379e7Schristos     {
1607*946379e7Schristos       token_ty tmp;
1608*946379e7Schristos       size_t len;
1609*946379e7Schristos 
1610*946379e7Schristos       phase5_get (&tmp);
1611*946379e7Schristos       if (tmp.type != token_type_string)
1612*946379e7Schristos 	{
1613*946379e7Schristos 	  phase5_unget (&tmp);
1614*946379e7Schristos 	  return;
1615*946379e7Schristos 	}
1616*946379e7Schristos       len = strlen (tp->string);
1617*946379e7Schristos       tp->string = xrealloc (tp->string, len + strlen (tmp.string) + 1);
1618*946379e7Schristos       strcpy (tp->string + len, tmp.string);
1619*946379e7Schristos       free (tmp.string);
1620*946379e7Schristos     }
1621*946379e7Schristos }
1622*946379e7Schristos 
1623*946379e7Schristos 
1624*946379e7Schristos /* ========================= Extracting strings.  ========================== */
1625*946379e7Schristos 
1626*946379e7Schristos 
1627*946379e7Schristos /* Context lookup table.  */
1628*946379e7Schristos static flag_context_list_table_ty *flag_context_list_table;
1629*946379e7Schristos 
1630*946379e7Schristos 
1631*946379e7Schristos /* The file is broken into tokens.  Scan the token stream, looking for
1632*946379e7Schristos    a keyword, followed by a left paren, followed by a string.  When we
1633*946379e7Schristos    see this sequence, we have something to remember.  We assume we are
1634*946379e7Schristos    looking at a valid C or C++ program, and leave the complaints about
1635*946379e7Schristos    the grammar to the compiler.
1636*946379e7Schristos 
1637*946379e7Schristos      Normal handling: Look for
1638*946379e7Schristos        keyword ( ... msgid ... )
1639*946379e7Schristos      Plural handling: Look for
1640*946379e7Schristos        keyword ( ... msgid ... msgid_plural ... )
1641*946379e7Schristos 
1642*946379e7Schristos    We use recursion because the arguments before msgid or between msgid
1643*946379e7Schristos    and msgid_plural can contain subexpressions of the same form.  */
1644*946379e7Schristos 
1645*946379e7Schristos 
1646*946379e7Schristos /* Extract messages until the next balanced closing parenthesis.
1647*946379e7Schristos    Extracted messages are added to MLP.
1648*946379e7Schristos    Return true upon eof, false upon closing parenthesis.  */
1649*946379e7Schristos static bool
extract_parenthesized(message_list_ty * mlp,flag_context_ty outer_context,flag_context_list_iterator_ty context_iter,struct arglist_parser * argparser)1650*946379e7Schristos extract_parenthesized (message_list_ty *mlp,
1651*946379e7Schristos 		       flag_context_ty outer_context,
1652*946379e7Schristos 		       flag_context_list_iterator_ty context_iter,
1653*946379e7Schristos 		       struct arglist_parser *argparser)
1654*946379e7Schristos {
1655*946379e7Schristos   /* Current argument number.  */
1656*946379e7Schristos   int arg = 1;
1657*946379e7Schristos   /* 0 when no keyword has been seen.  1 right after a keyword is seen.  */
1658*946379e7Schristos   int state;
1659*946379e7Schristos   /* Parameters of the keyword just seen.  Defined only in state 1.  */
1660*946379e7Schristos   const struct callshapes *next_shapes = NULL;
1661*946379e7Schristos   /* Context iterator that will be used if the next token is a '('.  */
1662*946379e7Schristos   flag_context_list_iterator_ty next_context_iter =
1663*946379e7Schristos     passthrough_context_list_iterator;
1664*946379e7Schristos   /* Current context.  */
1665*946379e7Schristos   flag_context_ty inner_context =
1666*946379e7Schristos     inherited_context (outer_context,
1667*946379e7Schristos 		       flag_context_list_iterator_advance (&context_iter));
1668*946379e7Schristos 
1669*946379e7Schristos   /* Start state is 0.  */
1670*946379e7Schristos   state = 0;
1671*946379e7Schristos 
1672*946379e7Schristos   for (;;)
1673*946379e7Schristos     {
1674*946379e7Schristos       token_ty token;
1675*946379e7Schristos 
1676*946379e7Schristos       x_python_lex (&token);
1677*946379e7Schristos       switch (token.type)
1678*946379e7Schristos 	{
1679*946379e7Schristos 	case token_type_symbol:
1680*946379e7Schristos 	  {
1681*946379e7Schristos 	    void *keyword_value;
1682*946379e7Schristos 
1683*946379e7Schristos 	    if (hash_find_entry (&keywords, token.string, strlen (token.string),
1684*946379e7Schristos 				 &keyword_value)
1685*946379e7Schristos 		== 0)
1686*946379e7Schristos 	      {
1687*946379e7Schristos 		next_shapes = (const struct callshapes *) keyword_value;
1688*946379e7Schristos 		state = 1;
1689*946379e7Schristos 	      }
1690*946379e7Schristos 	    else
1691*946379e7Schristos 	      state = 0;
1692*946379e7Schristos 	  }
1693*946379e7Schristos 	  next_context_iter =
1694*946379e7Schristos 	    flag_context_list_iterator (
1695*946379e7Schristos 	      flag_context_list_table_lookup (
1696*946379e7Schristos 		flag_context_list_table,
1697*946379e7Schristos 		token.string, strlen (token.string)));
1698*946379e7Schristos 	  free (token.string);
1699*946379e7Schristos 	  continue;
1700*946379e7Schristos 
1701*946379e7Schristos 	case token_type_lparen:
1702*946379e7Schristos 	  if (extract_parenthesized (mlp, inner_context, next_context_iter,
1703*946379e7Schristos 				     arglist_parser_alloc (mlp,
1704*946379e7Schristos 							   state ? next_shapes : NULL)))
1705*946379e7Schristos 	    {
1706*946379e7Schristos 	      xgettext_current_source_encoding = po_charset_utf8;
1707*946379e7Schristos 	      arglist_parser_done (argparser, arg);
1708*946379e7Schristos 	      xgettext_current_source_encoding = xgettext_current_file_source_encoding;
1709*946379e7Schristos 	      return true;
1710*946379e7Schristos 	    }
1711*946379e7Schristos 	  next_context_iter = null_context_list_iterator;
1712*946379e7Schristos 	  state = 0;
1713*946379e7Schristos 	  continue;
1714*946379e7Schristos 
1715*946379e7Schristos 	case token_type_rparen:
1716*946379e7Schristos 	  xgettext_current_source_encoding = po_charset_utf8;
1717*946379e7Schristos 	  arglist_parser_done (argparser, arg);
1718*946379e7Schristos 	  xgettext_current_source_encoding = xgettext_current_file_source_encoding;
1719*946379e7Schristos 	  return false;
1720*946379e7Schristos 
1721*946379e7Schristos 	case token_type_comma:
1722*946379e7Schristos 	  arg++;
1723*946379e7Schristos 	  inner_context =
1724*946379e7Schristos 	    inherited_context (outer_context,
1725*946379e7Schristos 			       flag_context_list_iterator_advance (
1726*946379e7Schristos 				 &context_iter));
1727*946379e7Schristos 	  next_context_iter = passthrough_context_list_iterator;
1728*946379e7Schristos 	  state = 0;
1729*946379e7Schristos 	  continue;
1730*946379e7Schristos 
1731*946379e7Schristos 	case token_type_string:
1732*946379e7Schristos 	  {
1733*946379e7Schristos 	    lex_pos_ty pos;
1734*946379e7Schristos 	    pos.file_name = logical_file_name;
1735*946379e7Schristos 	    pos.line_number = token.line_number;
1736*946379e7Schristos 
1737*946379e7Schristos 	    xgettext_current_source_encoding = po_charset_utf8;
1738*946379e7Schristos 	    if (extract_all)
1739*946379e7Schristos 	      remember_a_message (mlp, NULL, token.string, inner_context,
1740*946379e7Schristos 				  &pos, token.comment);
1741*946379e7Schristos 	    else
1742*946379e7Schristos 	      arglist_parser_remember (argparser, arg, token.string,
1743*946379e7Schristos 				       inner_context,
1744*946379e7Schristos 				       pos.file_name, pos.line_number,
1745*946379e7Schristos 				       token.comment);
1746*946379e7Schristos 	    xgettext_current_source_encoding = xgettext_current_file_source_encoding;
1747*946379e7Schristos 	  }
1748*946379e7Schristos 	  drop_reference (token.comment);
1749*946379e7Schristos 	  next_context_iter = null_context_list_iterator;
1750*946379e7Schristos 	  state = 0;
1751*946379e7Schristos 	  continue;
1752*946379e7Schristos 
1753*946379e7Schristos 	case token_type_eof:
1754*946379e7Schristos 	  xgettext_current_source_encoding = po_charset_utf8;
1755*946379e7Schristos 	  arglist_parser_done (argparser, arg);
1756*946379e7Schristos 	  xgettext_current_source_encoding = xgettext_current_file_source_encoding;
1757*946379e7Schristos 	  return true;
1758*946379e7Schristos 
1759*946379e7Schristos 	case token_type_other:
1760*946379e7Schristos 	  next_context_iter = null_context_list_iterator;
1761*946379e7Schristos 	  state = 0;
1762*946379e7Schristos 	  continue;
1763*946379e7Schristos 
1764*946379e7Schristos 	default:
1765*946379e7Schristos 	  abort ();
1766*946379e7Schristos 	}
1767*946379e7Schristos     }
1768*946379e7Schristos }
1769*946379e7Schristos 
1770*946379e7Schristos 
1771*946379e7Schristos void
extract_python(FILE * f,const char * real_filename,const char * logical_filename,flag_context_list_table_ty * flag_table,msgdomain_list_ty * mdlp)1772*946379e7Schristos extract_python (FILE *f,
1773*946379e7Schristos 		const char *real_filename, const char *logical_filename,
1774*946379e7Schristos 		flag_context_list_table_ty *flag_table,
1775*946379e7Schristos 		msgdomain_list_ty *mdlp)
1776*946379e7Schristos {
1777*946379e7Schristos   message_list_ty *mlp = mdlp->item[0]->messages;
1778*946379e7Schristos 
1779*946379e7Schristos   fp = f;
1780*946379e7Schristos   real_file_name = real_filename;
1781*946379e7Schristos   logical_file_name = xstrdup (logical_filename);
1782*946379e7Schristos   line_number = 1;
1783*946379e7Schristos 
1784*946379e7Schristos   last_comment_line = -1;
1785*946379e7Schristos   last_non_comment_line = -1;
1786*946379e7Schristos 
1787*946379e7Schristos   xgettext_current_file_source_encoding = xgettext_global_source_encoding;
1788*946379e7Schristos #if HAVE_ICONV
1789*946379e7Schristos   xgettext_current_file_source_iconv = xgettext_global_source_iconv;
1790*946379e7Schristos #endif
1791*946379e7Schristos 
1792*946379e7Schristos   xgettext_current_source_encoding = xgettext_current_file_source_encoding;
1793*946379e7Schristos #if HAVE_ICONV
1794*946379e7Schristos   xgettext_current_source_iconv = xgettext_current_file_source_iconv;
1795*946379e7Schristos #endif
1796*946379e7Schristos 
1797*946379e7Schristos   continuation_or_nonblank_line = false;
1798*946379e7Schristos 
1799*946379e7Schristos   open_pbb = 0;
1800*946379e7Schristos 
1801*946379e7Schristos   flag_context_list_table = flag_table;
1802*946379e7Schristos 
1803*946379e7Schristos   init_keywords ();
1804*946379e7Schristos 
1805*946379e7Schristos   /* Eat tokens until eof is seen.  When extract_parenthesized returns
1806*946379e7Schristos      due to an unbalanced closing parenthesis, just restart it.  */
1807*946379e7Schristos   while (!extract_parenthesized (mlp, null_context, null_context_list_iterator,
1808*946379e7Schristos 				 arglist_parser_alloc (mlp, NULL)))
1809*946379e7Schristos     ;
1810*946379e7Schristos 
1811*946379e7Schristos   fp = NULL;
1812*946379e7Schristos   real_file_name = NULL;
1813*946379e7Schristos   logical_file_name = NULL;
1814*946379e7Schristos   line_number = 0;
1815*946379e7Schristos }
1816