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