1*63eb84d1Schristos /* Reading PO files, abstract class.
2*63eb84d1Schristos    Copyright (C) 1995-1996, 1998, 2000-2006 Free Software Foundation, Inc.
3*63eb84d1Schristos 
4*63eb84d1Schristos    This file was written by Peter Miller <millerp@canb.auug.org.au>
5*63eb84d1Schristos 
6*63eb84d1Schristos    This program is free software; you can redistribute it and/or modify
7*63eb84d1Schristos    it under the terms of the GNU General Public License as published by
8*63eb84d1Schristos    the Free Software Foundation; either version 2, or (at your option)
9*63eb84d1Schristos    any later version.
10*63eb84d1Schristos 
11*63eb84d1Schristos    This program is distributed in the hope that it will be useful,
12*63eb84d1Schristos    but WITHOUT ANY WARRANTY; without even the implied warranty of
13*63eb84d1Schristos    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14*63eb84d1Schristos    GNU General Public License for more details.
15*63eb84d1Schristos 
16*63eb84d1Schristos    You should have received a copy of the GNU General Public License
17*63eb84d1Schristos    along with this program; if not, write to the Free Software Foundation,
18*63eb84d1Schristos    Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.  */
19*63eb84d1Schristos 
20*63eb84d1Schristos 
21*63eb84d1Schristos #ifdef HAVE_CONFIG_H
22*63eb84d1Schristos # include "config.h"
23*63eb84d1Schristos #endif
24*63eb84d1Schristos 
25*63eb84d1Schristos /* Specification.  */
26*63eb84d1Schristos #include "read-catalog-abstract.h"
27*63eb84d1Schristos 
28*63eb84d1Schristos #include <stdlib.h>
29*63eb84d1Schristos #include <string.h>
30*63eb84d1Schristos 
31*63eb84d1Schristos #include "xalloc.h"
32*63eb84d1Schristos #include "xvasprintf.h"
33*63eb84d1Schristos #include "po-xerror.h"
34*63eb84d1Schristos #include "gettext.h"
35*63eb84d1Schristos 
36*63eb84d1Schristos /* Local variables.  */
37*63eb84d1Schristos static abstract_catalog_reader_ty *callback_arg;
38*63eb84d1Schristos 
39*63eb84d1Schristos 
40*63eb84d1Schristos /* ========================================================================= */
41*63eb84d1Schristos /* Allocating and freeing instances of abstract_catalog_reader_ty.  */
42*63eb84d1Schristos 
43*63eb84d1Schristos 
44*63eb84d1Schristos abstract_catalog_reader_ty *
catalog_reader_alloc(abstract_catalog_reader_class_ty * method_table)45*63eb84d1Schristos catalog_reader_alloc (abstract_catalog_reader_class_ty *method_table)
46*63eb84d1Schristos {
47*63eb84d1Schristos   abstract_catalog_reader_ty *pop;
48*63eb84d1Schristos 
49*63eb84d1Schristos   pop = (abstract_catalog_reader_ty *) xmalloc (method_table->size);
50*63eb84d1Schristos   pop->methods = method_table;
51*63eb84d1Schristos   if (method_table->constructor)
52*63eb84d1Schristos     method_table->constructor (pop);
53*63eb84d1Schristos   return pop;
54*63eb84d1Schristos }
55*63eb84d1Schristos 
56*63eb84d1Schristos 
57*63eb84d1Schristos void
catalog_reader_free(abstract_catalog_reader_ty * pop)58*63eb84d1Schristos catalog_reader_free (abstract_catalog_reader_ty *pop)
59*63eb84d1Schristos {
60*63eb84d1Schristos   if (pop->methods->destructor)
61*63eb84d1Schristos     pop->methods->destructor (pop);
62*63eb84d1Schristos   free (pop);
63*63eb84d1Schristos }
64*63eb84d1Schristos 
65*63eb84d1Schristos 
66*63eb84d1Schristos /* ========================================================================= */
67*63eb84d1Schristos /* Inline functions to invoke the methods.  */
68*63eb84d1Schristos 
69*63eb84d1Schristos 
70*63eb84d1Schristos static inline void
call_parse_brief(abstract_catalog_reader_ty * pop)71*63eb84d1Schristos call_parse_brief (abstract_catalog_reader_ty *pop)
72*63eb84d1Schristos {
73*63eb84d1Schristos   if (pop->methods->parse_brief)
74*63eb84d1Schristos     pop->methods->parse_brief (pop);
75*63eb84d1Schristos }
76*63eb84d1Schristos 
77*63eb84d1Schristos static inline void
call_parse_debrief(abstract_catalog_reader_ty * pop)78*63eb84d1Schristos call_parse_debrief (abstract_catalog_reader_ty *pop)
79*63eb84d1Schristos {
80*63eb84d1Schristos   if (pop->methods->parse_debrief)
81*63eb84d1Schristos     pop->methods->parse_debrief (pop);
82*63eb84d1Schristos }
83*63eb84d1Schristos 
84*63eb84d1Schristos static inline void
call_directive_domain(abstract_catalog_reader_ty * pop,char * name)85*63eb84d1Schristos call_directive_domain (abstract_catalog_reader_ty *pop, char *name)
86*63eb84d1Schristos {
87*63eb84d1Schristos   if (pop->methods->directive_domain)
88*63eb84d1Schristos     pop->methods->directive_domain (pop, name);
89*63eb84d1Schristos }
90*63eb84d1Schristos 
91*63eb84d1Schristos static inline void
call_directive_message(abstract_catalog_reader_ty * pop,char * msgctxt,char * msgid,lex_pos_ty * msgid_pos,char * msgid_plural,char * msgstr,size_t msgstr_len,lex_pos_ty * msgstr_pos,char * prev_msgctxt,char * prev_msgid,char * prev_msgid_plural,bool force_fuzzy,bool obsolete)92*63eb84d1Schristos call_directive_message (abstract_catalog_reader_ty *pop,
93*63eb84d1Schristos 			char *msgctxt,
94*63eb84d1Schristos 			char *msgid,
95*63eb84d1Schristos 			lex_pos_ty *msgid_pos,
96*63eb84d1Schristos 			char *msgid_plural,
97*63eb84d1Schristos 			char *msgstr, size_t msgstr_len,
98*63eb84d1Schristos 			lex_pos_ty *msgstr_pos,
99*63eb84d1Schristos 			char *prev_msgctxt,
100*63eb84d1Schristos 			char *prev_msgid,
101*63eb84d1Schristos 			char *prev_msgid_plural,
102*63eb84d1Schristos 			bool force_fuzzy, bool obsolete)
103*63eb84d1Schristos {
104*63eb84d1Schristos   if (pop->methods->directive_message)
105*63eb84d1Schristos     pop->methods->directive_message (pop, msgctxt,
106*63eb84d1Schristos 				     msgid, msgid_pos, msgid_plural,
107*63eb84d1Schristos 				     msgstr, msgstr_len, msgstr_pos,
108*63eb84d1Schristos 				     prev_msgctxt,
109*63eb84d1Schristos 				     prev_msgid,
110*63eb84d1Schristos 				     prev_msgid_plural,
111*63eb84d1Schristos 				     force_fuzzy, obsolete);
112*63eb84d1Schristos }
113*63eb84d1Schristos 
114*63eb84d1Schristos static inline void
call_comment(abstract_catalog_reader_ty * pop,const char * s)115*63eb84d1Schristos call_comment (abstract_catalog_reader_ty *pop, const char *s)
116*63eb84d1Schristos {
117*63eb84d1Schristos   if (pop->methods->comment != NULL)
118*63eb84d1Schristos     pop->methods->comment (pop, s);
119*63eb84d1Schristos }
120*63eb84d1Schristos 
121*63eb84d1Schristos static inline void
call_comment_dot(abstract_catalog_reader_ty * pop,const char * s)122*63eb84d1Schristos call_comment_dot (abstract_catalog_reader_ty *pop, const char *s)
123*63eb84d1Schristos {
124*63eb84d1Schristos   if (pop->methods->comment_dot != NULL)
125*63eb84d1Schristos     pop->methods->comment_dot (pop, s);
126*63eb84d1Schristos }
127*63eb84d1Schristos 
128*63eb84d1Schristos static inline void
call_comment_filepos(abstract_catalog_reader_ty * pop,const char * name,size_t line)129*63eb84d1Schristos call_comment_filepos (abstract_catalog_reader_ty *pop, const char *name,
130*63eb84d1Schristos 		      size_t line)
131*63eb84d1Schristos {
132*63eb84d1Schristos   if (pop->methods->comment_filepos)
133*63eb84d1Schristos     pop->methods->comment_filepos (pop, name, line);
134*63eb84d1Schristos }
135*63eb84d1Schristos 
136*63eb84d1Schristos static inline void
call_comment_special(abstract_catalog_reader_ty * pop,const char * s)137*63eb84d1Schristos call_comment_special (abstract_catalog_reader_ty *pop, const char *s)
138*63eb84d1Schristos {
139*63eb84d1Schristos   if (pop->methods->comment_special != NULL)
140*63eb84d1Schristos     pop->methods->comment_special (pop, s);
141*63eb84d1Schristos }
142*63eb84d1Schristos 
143*63eb84d1Schristos 
144*63eb84d1Schristos /* ========================================================================= */
145*63eb84d1Schristos /* Exported functions.  */
146*63eb84d1Schristos 
147*63eb84d1Schristos 
148*63eb84d1Schristos static inline void
parse_start(abstract_catalog_reader_ty * pop)149*63eb84d1Schristos parse_start (abstract_catalog_reader_ty *pop)
150*63eb84d1Schristos {
151*63eb84d1Schristos   /* The parse will call the po_callback_... functions (see below)
152*63eb84d1Schristos      when the various directive are recognised.  The callback_arg
153*63eb84d1Schristos      variable is used to tell these functions which instance is to
154*63eb84d1Schristos      have the relevant method invoked.  */
155*63eb84d1Schristos   callback_arg = pop;
156*63eb84d1Schristos 
157*63eb84d1Schristos   call_parse_brief (pop);
158*63eb84d1Schristos }
159*63eb84d1Schristos 
160*63eb84d1Schristos static inline void
parse_end(abstract_catalog_reader_ty * pop)161*63eb84d1Schristos parse_end (abstract_catalog_reader_ty *pop)
162*63eb84d1Schristos {
163*63eb84d1Schristos   call_parse_debrief (pop);
164*63eb84d1Schristos   callback_arg = NULL;
165*63eb84d1Schristos }
166*63eb84d1Schristos 
167*63eb84d1Schristos 
168*63eb84d1Schristos void
catalog_reader_parse(abstract_catalog_reader_ty * pop,FILE * fp,const char * real_filename,const char * logical_filename,catalog_input_format_ty input_syntax)169*63eb84d1Schristos catalog_reader_parse (abstract_catalog_reader_ty *pop, FILE *fp,
170*63eb84d1Schristos 		      const char *real_filename, const char *logical_filename,
171*63eb84d1Schristos 		      catalog_input_format_ty input_syntax)
172*63eb84d1Schristos {
173*63eb84d1Schristos   /* Parse the stream's content.  */
174*63eb84d1Schristos   parse_start (pop);
175*63eb84d1Schristos   input_syntax->parse (pop, fp, real_filename, logical_filename);
176*63eb84d1Schristos   parse_end (pop);
177*63eb84d1Schristos 
178*63eb84d1Schristos   if (error_message_count > 0)
179*63eb84d1Schristos     po_xerror (PO_SEVERITY_FATAL_ERROR, NULL,
180*63eb84d1Schristos 	       /*real_filename*/ NULL, (size_t)(-1), (size_t)(-1), false,
181*63eb84d1Schristos 	       xasprintf (ngettext ("found %d fatal error",
182*63eb84d1Schristos 				    "found %d fatal errors",
183*63eb84d1Schristos 				    error_message_count),
184*63eb84d1Schristos 			  error_message_count));
185*63eb84d1Schristos   error_message_count = 0;
186*63eb84d1Schristos }
187*63eb84d1Schristos 
188*63eb84d1Schristos 
189*63eb84d1Schristos /* ========================================================================= */
190*63eb84d1Schristos /* Callbacks used by po-gram.y or po-lex.c, indirectly from
191*63eb84d1Schristos    catalog_reader_parse.  */
192*63eb84d1Schristos 
193*63eb84d1Schristos 
194*63eb84d1Schristos /* This function is called by po_gram_lex() whenever a domain directive
195*63eb84d1Schristos    has been seen.  */
196*63eb84d1Schristos void
po_callback_domain(char * name)197*63eb84d1Schristos po_callback_domain (char *name)
198*63eb84d1Schristos {
199*63eb84d1Schristos   /* assert(callback_arg); */
200*63eb84d1Schristos   call_directive_domain (callback_arg, name);
201*63eb84d1Schristos }
202*63eb84d1Schristos 
203*63eb84d1Schristos 
204*63eb84d1Schristos /* This function is called by po_gram_lex() whenever a message has been
205*63eb84d1Schristos    seen.  */
206*63eb84d1Schristos void
po_callback_message(char * msgctxt,char * msgid,lex_pos_ty * msgid_pos,char * msgid_plural,char * msgstr,size_t msgstr_len,lex_pos_ty * msgstr_pos,char * prev_msgctxt,char * prev_msgid,char * prev_msgid_plural,bool force_fuzzy,bool obsolete)207*63eb84d1Schristos po_callback_message (char *msgctxt,
208*63eb84d1Schristos 		     char *msgid, lex_pos_ty *msgid_pos, char *msgid_plural,
209*63eb84d1Schristos 		     char *msgstr, size_t msgstr_len, lex_pos_ty *msgstr_pos,
210*63eb84d1Schristos 		     char *prev_msgctxt,
211*63eb84d1Schristos 		     char *prev_msgid,
212*63eb84d1Schristos 		     char *prev_msgid_plural,
213*63eb84d1Schristos 		     bool force_fuzzy, bool obsolete)
214*63eb84d1Schristos {
215*63eb84d1Schristos   /* assert(callback_arg); */
216*63eb84d1Schristos   call_directive_message (callback_arg, msgctxt,
217*63eb84d1Schristos 			  msgid, msgid_pos, msgid_plural,
218*63eb84d1Schristos 			  msgstr, msgstr_len, msgstr_pos,
219*63eb84d1Schristos 			  prev_msgctxt, prev_msgid, prev_msgid_plural,
220*63eb84d1Schristos 			  force_fuzzy, obsolete);
221*63eb84d1Schristos }
222*63eb84d1Schristos 
223*63eb84d1Schristos 
224*63eb84d1Schristos void
po_callback_comment(const char * s)225*63eb84d1Schristos po_callback_comment (const char *s)
226*63eb84d1Schristos {
227*63eb84d1Schristos   /* assert(callback_arg); */
228*63eb84d1Schristos   call_comment (callback_arg, s);
229*63eb84d1Schristos }
230*63eb84d1Schristos 
231*63eb84d1Schristos 
232*63eb84d1Schristos void
po_callback_comment_dot(const char * s)233*63eb84d1Schristos po_callback_comment_dot (const char *s)
234*63eb84d1Schristos {
235*63eb84d1Schristos   /* assert(callback_arg); */
236*63eb84d1Schristos   call_comment_dot (callback_arg, s);
237*63eb84d1Schristos }
238*63eb84d1Schristos 
239*63eb84d1Schristos 
240*63eb84d1Schristos /* This function is called by po_parse_comment_filepos(), once for each
241*63eb84d1Schristos    filename.  */
242*63eb84d1Schristos void
po_callback_comment_filepos(const char * name,size_t line)243*63eb84d1Schristos po_callback_comment_filepos (const char *name, size_t line)
244*63eb84d1Schristos {
245*63eb84d1Schristos   /* assert(callback_arg); */
246*63eb84d1Schristos   call_comment_filepos (callback_arg, name, line);
247*63eb84d1Schristos }
248*63eb84d1Schristos 
249*63eb84d1Schristos 
250*63eb84d1Schristos void
po_callback_comment_special(const char * s)251*63eb84d1Schristos po_callback_comment_special (const char *s)
252*63eb84d1Schristos {
253*63eb84d1Schristos   /* assert(callback_arg); */
254*63eb84d1Schristos   call_comment_special (callback_arg, s);
255*63eb84d1Schristos }
256*63eb84d1Schristos 
257*63eb84d1Schristos 
258*63eb84d1Schristos /* Parse a special comment and put the result in *fuzzyp, formatp, *wrapp.  */
259*63eb84d1Schristos void
po_parse_comment_special(const char * s,bool * fuzzyp,enum is_format formatp[NFORMATS],enum is_wrap * wrapp)260*63eb84d1Schristos po_parse_comment_special (const char *s,
261*63eb84d1Schristos 			  bool *fuzzyp, enum is_format formatp[NFORMATS],
262*63eb84d1Schristos 			  enum is_wrap *wrapp)
263*63eb84d1Schristos {
264*63eb84d1Schristos   size_t i;
265*63eb84d1Schristos 
266*63eb84d1Schristos   *fuzzyp = false;
267*63eb84d1Schristos   for (i = 0; i < NFORMATS; i++)
268*63eb84d1Schristos     formatp[i] = undecided;
269*63eb84d1Schristos   *wrapp = undecided;
270*63eb84d1Schristos 
271*63eb84d1Schristos   while (*s != '\0')
272*63eb84d1Schristos     {
273*63eb84d1Schristos       const char *t;
274*63eb84d1Schristos 
275*63eb84d1Schristos       /* Skip whitespace.  */
276*63eb84d1Schristos       while (*s != '\0' && strchr ("\n \t\r\f\v,", *s) != NULL)
277*63eb84d1Schristos 	s++;
278*63eb84d1Schristos 
279*63eb84d1Schristos       /* Collect a token.  */
280*63eb84d1Schristos       t = s;
281*63eb84d1Schristos       while (*s != '\0' && strchr ("\n \t\r\f\v,", *s) == NULL)
282*63eb84d1Schristos 	s++;
283*63eb84d1Schristos       if (s != t)
284*63eb84d1Schristos 	{
285*63eb84d1Schristos 	  size_t len = s - t;
286*63eb84d1Schristos 
287*63eb84d1Schristos 	  /* Accept fuzzy flag.  */
288*63eb84d1Schristos 	  if (len == 5 && memcmp (t, "fuzzy", 5) == 0)
289*63eb84d1Schristos 	    {
290*63eb84d1Schristos 	      *fuzzyp = true;
291*63eb84d1Schristos 	      continue;
292*63eb84d1Schristos 	    }
293*63eb84d1Schristos 
294*63eb84d1Schristos 	  /* Accept format description.  */
295*63eb84d1Schristos 	  if (len >= 7 && memcmp (t + len - 7, "-format", 7) == 0)
296*63eb84d1Schristos 	    {
297*63eb84d1Schristos 	      const char *p;
298*63eb84d1Schristos 	      size_t n;
299*63eb84d1Schristos 	      enum is_format value;
300*63eb84d1Schristos 
301*63eb84d1Schristos 	      p = t;
302*63eb84d1Schristos 	      n = len - 7;
303*63eb84d1Schristos 
304*63eb84d1Schristos 	      if (n >= 3 && memcmp (p, "no-", 3) == 0)
305*63eb84d1Schristos 		{
306*63eb84d1Schristos 		  p += 3;
307*63eb84d1Schristos 		  n -= 3;
308*63eb84d1Schristos 		  value = no;
309*63eb84d1Schristos 		}
310*63eb84d1Schristos 	      else if (n >= 9 && memcmp (p, "possible-", 9) == 0)
311*63eb84d1Schristos 		{
312*63eb84d1Schristos 		  p += 9;
313*63eb84d1Schristos 		  n -= 9;
314*63eb84d1Schristos 		  value = possible;
315*63eb84d1Schristos 		}
316*63eb84d1Schristos 	      else if (n >= 11 && memcmp (p, "impossible-", 11) == 0)
317*63eb84d1Schristos 		{
318*63eb84d1Schristos 		  p += 11;
319*63eb84d1Schristos 		  n -= 11;
320*63eb84d1Schristos 		  value = impossible;
321*63eb84d1Schristos 		}
322*63eb84d1Schristos 	      else
323*63eb84d1Schristos 		value = yes;
324*63eb84d1Schristos 
325*63eb84d1Schristos 	      for (i = 0; i < NFORMATS; i++)
326*63eb84d1Schristos 		if (strlen (format_language[i]) == n
327*63eb84d1Schristos 		    && memcmp (format_language[i], p, n) == 0)
328*63eb84d1Schristos 		  {
329*63eb84d1Schristos 		    formatp[i] = value;
330*63eb84d1Schristos 		    break;
331*63eb84d1Schristos 		  }
332*63eb84d1Schristos 	      if (i < NFORMATS)
333*63eb84d1Schristos 		continue;
334*63eb84d1Schristos 	    }
335*63eb84d1Schristos 
336*63eb84d1Schristos 	  /* Accept wrap description.  */
337*63eb84d1Schristos 	  if (len == 4 && memcmp (t, "wrap", 4) == 0)
338*63eb84d1Schristos 	    {
339*63eb84d1Schristos 	      *wrapp = yes;
340*63eb84d1Schristos 	      continue;
341*63eb84d1Schristos 	    }
342*63eb84d1Schristos 	  if (len == 7 && memcmp (t, "no-wrap", 7) == 0)
343*63eb84d1Schristos 	    {
344*63eb84d1Schristos 	      *wrapp = no;
345*63eb84d1Schristos 	      continue;
346*63eb84d1Schristos 	    }
347*63eb84d1Schristos 
348*63eb84d1Schristos 	  /* Unknown special comment marker.  It may have been generated
349*63eb84d1Schristos 	     from a future xgettext version.  Ignore it.  */
350*63eb84d1Schristos 	}
351*63eb84d1Schristos     }
352*63eb84d1Schristos }
353*63eb84d1Schristos 
354*63eb84d1Schristos 
355*63eb84d1Schristos /* Parse a GNU style file comment.
356*63eb84d1Schristos    Syntax: an arbitrary number of
357*63eb84d1Schristos              STRING COLON NUMBER
358*63eb84d1Schristos            or
359*63eb84d1Schristos              STRING
360*63eb84d1Schristos    The latter style, without line number, occurs in PO files converted e.g.
361*63eb84d1Schristos    from Pascal .rst files or from OpenOffice resource files.
362*63eb84d1Schristos    Call po_callback_comment_filepos for each of them.  */
363*63eb84d1Schristos static void
po_parse_comment_filepos(const char * s)364*63eb84d1Schristos po_parse_comment_filepos (const char *s)
365*63eb84d1Schristos {
366*63eb84d1Schristos   while (*s != '\0')
367*63eb84d1Schristos     {
368*63eb84d1Schristos       while (*s == ' ' || *s == '\t' || *s == '\n')
369*63eb84d1Schristos 	s++;
370*63eb84d1Schristos       if (*s != '\0')
371*63eb84d1Schristos 	{
372*63eb84d1Schristos 	  const char *string_start = s;
373*63eb84d1Schristos 
374*63eb84d1Schristos 	  do
375*63eb84d1Schristos 	    s++;
376*63eb84d1Schristos 	  while (!(*s == '\0' || *s == ' ' || *s == '\t' || *s == '\n'));
377*63eb84d1Schristos 
378*63eb84d1Schristos 	  /* See if there is a COLON and NUMBER after the STRING, separated
379*63eb84d1Schristos 	     through optional spaces.  */
380*63eb84d1Schristos 	  {
381*63eb84d1Schristos 	    const char *p = s;
382*63eb84d1Schristos 
383*63eb84d1Schristos 	    while (*p == ' ' || *p == '\t' || *p == '\n')
384*63eb84d1Schristos 	      p++;
385*63eb84d1Schristos 
386*63eb84d1Schristos 	    if (*p == ':')
387*63eb84d1Schristos 	      {
388*63eb84d1Schristos 		p++;
389*63eb84d1Schristos 
390*63eb84d1Schristos 		while (*p == ' ' || *p == '\t' || *p == '\n')
391*63eb84d1Schristos 		  p++;
392*63eb84d1Schristos 
393*63eb84d1Schristos 		if (*p >= '0' && *p <= '9')
394*63eb84d1Schristos 		  {
395*63eb84d1Schristos 		    /* Accumulate a number.  */
396*63eb84d1Schristos 		    size_t n = 0;
397*63eb84d1Schristos 
398*63eb84d1Schristos 		    do
399*63eb84d1Schristos 		      {
400*63eb84d1Schristos 			n = n * 10 + (*p - '0');
401*63eb84d1Schristos 			p++;
402*63eb84d1Schristos 		      }
403*63eb84d1Schristos 		    while (*p >= '0' && *p <= '9');
404*63eb84d1Schristos 
405*63eb84d1Schristos 		    if (*p == '\0' || *p == ' ' || *p == '\t' || *p == '\n')
406*63eb84d1Schristos 		      {
407*63eb84d1Schristos 			/* Parsed a GNU style file comment with spaces.  */
408*63eb84d1Schristos 			const char *string_end = s;
409*63eb84d1Schristos 			size_t string_length = string_end - string_start;
410*63eb84d1Schristos 			char *string = (char *) xmalloc (string_length + 1);
411*63eb84d1Schristos 
412*63eb84d1Schristos 			memcpy (string, string_start, string_length);
413*63eb84d1Schristos 			string[string_length] = '\0';
414*63eb84d1Schristos 
415*63eb84d1Schristos 			po_callback_comment_filepos (string, n);
416*63eb84d1Schristos 
417*63eb84d1Schristos 			free (string);
418*63eb84d1Schristos 
419*63eb84d1Schristos 			s = p;
420*63eb84d1Schristos 			continue;
421*63eb84d1Schristos 		      }
422*63eb84d1Schristos 		  }
423*63eb84d1Schristos 	      }
424*63eb84d1Schristos 	  }
425*63eb84d1Schristos 
426*63eb84d1Schristos 	  /* See if there is a COLON at the end of STRING and a NUMBER after
427*63eb84d1Schristos 	     it, separated through optional spaces.  */
428*63eb84d1Schristos 	  if (s[-1] == ':')
429*63eb84d1Schristos 	    {
430*63eb84d1Schristos 	      const char *p = s;
431*63eb84d1Schristos 
432*63eb84d1Schristos 	      while (*p == ' ' || *p == '\t' || *p == '\n')
433*63eb84d1Schristos 		p++;
434*63eb84d1Schristos 
435*63eb84d1Schristos 	      if (*p >= '0' && *p <= '9')
436*63eb84d1Schristos 		{
437*63eb84d1Schristos 		  /* Accumulate a number.  */
438*63eb84d1Schristos 		  size_t n = 0;
439*63eb84d1Schristos 
440*63eb84d1Schristos 		  do
441*63eb84d1Schristos 		    {
442*63eb84d1Schristos 		      n = n * 10 + (*p - '0');
443*63eb84d1Schristos 		      p++;
444*63eb84d1Schristos 		    }
445*63eb84d1Schristos 		  while (*p >= '0' && *p <= '9');
446*63eb84d1Schristos 
447*63eb84d1Schristos 		  if (*p == '\0' || *p == ' ' || *p == '\t' || *p == '\n')
448*63eb84d1Schristos 		    {
449*63eb84d1Schristos 		      /* Parsed a GNU style file comment with spaces.  */
450*63eb84d1Schristos 		      const char *string_end = s - 1;
451*63eb84d1Schristos 		      size_t string_length = string_end - string_start;
452*63eb84d1Schristos 		      char *string = (char *) xmalloc (string_length + 1);
453*63eb84d1Schristos 
454*63eb84d1Schristos 		      memcpy (string, string_start, string_length);
455*63eb84d1Schristos 		      string[string_length] = '\0';
456*63eb84d1Schristos 
457*63eb84d1Schristos 		      po_callback_comment_filepos (string, n);
458*63eb84d1Schristos 
459*63eb84d1Schristos 		      free (string);
460*63eb84d1Schristos 
461*63eb84d1Schristos 		      s = p;
462*63eb84d1Schristos 		      continue;
463*63eb84d1Schristos 		    }
464*63eb84d1Schristos 		}
465*63eb84d1Schristos 	    }
466*63eb84d1Schristos 
467*63eb84d1Schristos 	  /* See if there is a COLON and NUMBER at the end of the STRING,
468*63eb84d1Schristos 	     without separating spaces.  */
469*63eb84d1Schristos 	  {
470*63eb84d1Schristos 	    const char *p = s;
471*63eb84d1Schristos 
472*63eb84d1Schristos 	    while (p > string_start)
473*63eb84d1Schristos 	      {
474*63eb84d1Schristos 		p--;
475*63eb84d1Schristos 		if (!(*p >= '0' && *p <= '9'))
476*63eb84d1Schristos 		  {
477*63eb84d1Schristos 		    p++;
478*63eb84d1Schristos 		    break;
479*63eb84d1Schristos 		  }
480*63eb84d1Schristos 	      }
481*63eb84d1Schristos 
482*63eb84d1Schristos 	    /* p now points to the beginning of the trailing digits segment
483*63eb84d1Schristos 	       at the end of STRING.  */
484*63eb84d1Schristos 
485*63eb84d1Schristos 	    if (p < s
486*63eb84d1Schristos 		&& p > string_start + 1
487*63eb84d1Schristos 		&& p[-1] == ':')
488*63eb84d1Schristos 	      {
489*63eb84d1Schristos 		/* Parsed a GNU style file comment without spaces.  */
490*63eb84d1Schristos 		const char *string_end = p - 1;
491*63eb84d1Schristos 
492*63eb84d1Schristos 		/* Accumulate a number.  */
493*63eb84d1Schristos 		{
494*63eb84d1Schristos 		  size_t n = 0;
495*63eb84d1Schristos 
496*63eb84d1Schristos 		  do
497*63eb84d1Schristos 		    {
498*63eb84d1Schristos 		      n = n * 10 + (*p - '0');
499*63eb84d1Schristos 		      p++;
500*63eb84d1Schristos 		    }
501*63eb84d1Schristos 		  while (p < s);
502*63eb84d1Schristos 
503*63eb84d1Schristos 		  {
504*63eb84d1Schristos 		    size_t string_length = string_end - string_start;
505*63eb84d1Schristos 		    char *string = (char *) xmalloc (string_length + 1);
506*63eb84d1Schristos 
507*63eb84d1Schristos 		    memcpy (string, string_start, string_length);
508*63eb84d1Schristos 		    string[string_length] = '\0';
509*63eb84d1Schristos 
510*63eb84d1Schristos 		    po_callback_comment_filepos (string, n);
511*63eb84d1Schristos 
512*63eb84d1Schristos 		    free (string);
513*63eb84d1Schristos 
514*63eb84d1Schristos 		    continue;
515*63eb84d1Schristos 		  }
516*63eb84d1Schristos 		}
517*63eb84d1Schristos 	      }
518*63eb84d1Schristos 	  }
519*63eb84d1Schristos 
520*63eb84d1Schristos 	  /* Parsed a file comment without line number.  */
521*63eb84d1Schristos 	  {
522*63eb84d1Schristos 	    const char *string_end = s;
523*63eb84d1Schristos 	    size_t string_length = string_end - string_start;
524*63eb84d1Schristos 	    char *string = (char *) xmalloc (string_length + 1);
525*63eb84d1Schristos 
526*63eb84d1Schristos 	    memcpy (string, string_start, string_length);
527*63eb84d1Schristos 	    string[string_length] = '\0';
528*63eb84d1Schristos 
529*63eb84d1Schristos 	    po_callback_comment_filepos (string, (size_t)(-1));
530*63eb84d1Schristos 
531*63eb84d1Schristos 	    free (string);
532*63eb84d1Schristos 	  }
533*63eb84d1Schristos 	}
534*63eb84d1Schristos     }
535*63eb84d1Schristos }
536*63eb84d1Schristos 
537*63eb84d1Schristos 
538*63eb84d1Schristos /* Parse a SunOS or Solaris style file comment.
539*63eb84d1Schristos    Syntax of SunOS style:
540*63eb84d1Schristos      FILE_KEYWORD COLON STRING COMMA LINE_KEYWORD COLON NUMBER
541*63eb84d1Schristos    Syntax of Solaris style:
542*63eb84d1Schristos      FILE_KEYWORD COLON STRING COMMA LINE_KEYWORD NUMBER_KEYWORD COLON NUMBER
543*63eb84d1Schristos    where
544*63eb84d1Schristos      FILE_KEYWORD ::= "file" | "File"
545*63eb84d1Schristos      COLON ::= ":"
546*63eb84d1Schristos      COMMA ::= ","
547*63eb84d1Schristos      LINE_KEYWORD ::= "line"
548*63eb84d1Schristos      NUMBER_KEYWORD ::= "number"
549*63eb84d1Schristos      NUMBER ::= [0-9]+
550*63eb84d1Schristos    Return true if parsed, false if not a comment of this form. */
551*63eb84d1Schristos static bool
po_parse_comment_solaris_filepos(const char * s)552*63eb84d1Schristos po_parse_comment_solaris_filepos (const char *s)
553*63eb84d1Schristos {
554*63eb84d1Schristos   if (s[0] == ' '
555*63eb84d1Schristos       && (s[1] == 'F' || s[1] == 'f')
556*63eb84d1Schristos       && s[2] == 'i' && s[3] == 'l' && s[4] == 'e'
557*63eb84d1Schristos       && s[5] == ':')
558*63eb84d1Schristos     {
559*63eb84d1Schristos       const char *string_start;
560*63eb84d1Schristos       const char *string_end;
561*63eb84d1Schristos 
562*63eb84d1Schristos       {
563*63eb84d1Schristos 	const char *p = s + 6;
564*63eb84d1Schristos 
565*63eb84d1Schristos 	while (*p == ' ' || *p == '\t')
566*63eb84d1Schristos 	  p++;
567*63eb84d1Schristos 	string_start = p;
568*63eb84d1Schristos       }
569*63eb84d1Schristos 
570*63eb84d1Schristos       for (string_end = string_start; *string_end != '\0'; string_end++)
571*63eb84d1Schristos 	{
572*63eb84d1Schristos 	  const char *p = string_end;
573*63eb84d1Schristos 
574*63eb84d1Schristos 	  while (*p == ' ' || *p == '\t')
575*63eb84d1Schristos 	    p++;
576*63eb84d1Schristos 
577*63eb84d1Schristos 	  if (*p == ',')
578*63eb84d1Schristos 	    {
579*63eb84d1Schristos 	      p++;
580*63eb84d1Schristos 
581*63eb84d1Schristos 	      while (*p == ' ' || *p == '\t')
582*63eb84d1Schristos 		p++;
583*63eb84d1Schristos 
584*63eb84d1Schristos 	      if (p[0] == 'l' && p[1] == 'i' && p[2] == 'n' && p[3] == 'e')
585*63eb84d1Schristos 		{
586*63eb84d1Schristos 		  p += 4;
587*63eb84d1Schristos 
588*63eb84d1Schristos 		  while (*p == ' ' || *p == '\t')
589*63eb84d1Schristos 		    p++;
590*63eb84d1Schristos 
591*63eb84d1Schristos 		  if (p[0] == 'n' && p[1] == 'u' && p[2] == 'm'
592*63eb84d1Schristos 		      && p[3] == 'b' && p[4] == 'e' && p[5] == 'r')
593*63eb84d1Schristos 		    {
594*63eb84d1Schristos 		      p += 6;
595*63eb84d1Schristos 		      while (*p == ' ' || *p == '\t')
596*63eb84d1Schristos 			p++;
597*63eb84d1Schristos 		    }
598*63eb84d1Schristos 
599*63eb84d1Schristos 		  if (*p == ':')
600*63eb84d1Schristos 		    {
601*63eb84d1Schristos 		      p++;
602*63eb84d1Schristos 
603*63eb84d1Schristos 		      if (*p >= '0' && *p <= '9')
604*63eb84d1Schristos 			{
605*63eb84d1Schristos 			  /* Accumulate a number.  */
606*63eb84d1Schristos 			  size_t n = 0;
607*63eb84d1Schristos 
608*63eb84d1Schristos 			  do
609*63eb84d1Schristos 			    {
610*63eb84d1Schristos 			      n = n * 10 + (*p - '0');
611*63eb84d1Schristos 			      p++;
612*63eb84d1Schristos 			    }
613*63eb84d1Schristos 			  while (*p >= '0' && *p <= '9');
614*63eb84d1Schristos 
615*63eb84d1Schristos 			  while (*p == ' ' || *p == '\t' || *p == '\n')
616*63eb84d1Schristos 			    p++;
617*63eb84d1Schristos 
618*63eb84d1Schristos 			  if (*p == '\0')
619*63eb84d1Schristos 			    {
620*63eb84d1Schristos 			      /* Parsed a Sun style file comment.  */
621*63eb84d1Schristos 			      size_t string_length = string_end - string_start;
622*63eb84d1Schristos 			      char *string =
623*63eb84d1Schristos 				(char *) xmalloc (string_length + 1);
624*63eb84d1Schristos 
625*63eb84d1Schristos 			      memcpy (string, string_start, string_length);
626*63eb84d1Schristos 			      string[string_length] = '\0';
627*63eb84d1Schristos 
628*63eb84d1Schristos 			      po_callback_comment_filepos (string, n);
629*63eb84d1Schristos 
630*63eb84d1Schristos 			      free (string);
631*63eb84d1Schristos 			      return true;
632*63eb84d1Schristos 			    }
633*63eb84d1Schristos 			}
634*63eb84d1Schristos 		    }
635*63eb84d1Schristos 		}
636*63eb84d1Schristos 	    }
637*63eb84d1Schristos 	}
638*63eb84d1Schristos     }
639*63eb84d1Schristos 
640*63eb84d1Schristos   return false;
641*63eb84d1Schristos }
642*63eb84d1Schristos 
643*63eb84d1Schristos 
644*63eb84d1Schristos /* This function is called by po_gram_lex() whenever a comment is
645*63eb84d1Schristos    seen.  It analyzes the comment to see what sort it is, and then
646*63eb84d1Schristos    dispatches it to the appropriate method: call_comment, call_comment_dot,
647*63eb84d1Schristos    call_comment_filepos (via po_parse_comment_filepos), or
648*63eb84d1Schristos    call_comment_special.  */
649*63eb84d1Schristos void
po_callback_comment_dispatcher(const char * s)650*63eb84d1Schristos po_callback_comment_dispatcher (const char *s)
651*63eb84d1Schristos {
652*63eb84d1Schristos   if (*s == '.')
653*63eb84d1Schristos     po_callback_comment_dot (s + 1);
654*63eb84d1Schristos   else if (*s == ':')
655*63eb84d1Schristos     {
656*63eb84d1Schristos       /* Parse the file location string.  The appropriate callback will be
657*63eb84d1Schristos 	 invoked.  */
658*63eb84d1Schristos       po_parse_comment_filepos (s + 1);
659*63eb84d1Schristos     }
660*63eb84d1Schristos   else if (*s == ',' || *s == '!')
661*63eb84d1Schristos     {
662*63eb84d1Schristos       /* Get all entries in the special comment line.  */
663*63eb84d1Schristos       po_callback_comment_special (s + 1);
664*63eb84d1Schristos     }
665*63eb84d1Schristos   else
666*63eb84d1Schristos     {
667*63eb84d1Schristos       /* It looks like a plain vanilla comment, but Solaris-style file
668*63eb84d1Schristos 	 position lines do, too.  Try to parse the lot.  If the parse
669*63eb84d1Schristos 	 succeeds, the appropriate callback will be invoked.  */
670*63eb84d1Schristos       if (po_parse_comment_solaris_filepos (s))
671*63eb84d1Schristos 	/* Do nothing, it is a Sun-style file pos line.  */ ;
672*63eb84d1Schristos       else
673*63eb84d1Schristos 	po_callback_comment (s);
674*63eb84d1Schristos     }
675*63eb84d1Schristos }
676