1/* xgettext RST backend.
2   Copyright (C) 2001-2003, 2005 Free Software Foundation, Inc.
3
4   This file was written by Bruno Haible <haible@clisp.cons.org>, 2001.
5
6   This program is free software; you can redistribute it and/or modify
7   it under the terms of the GNU General Public License as published by
8   the Free Software Foundation; either version 2, or (at your option)
9   any later version.
10
11   This program is distributed in the hope that it will be useful,
12   but WITHOUT ANY WARRANTY; without even the implied warranty of
13   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14   GNU General Public License for more details.
15
16   You should have received a copy of the GNU General Public License
17   along with this program; if not, write to the Free Software Foundation,
18   Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.  */
19
20#ifdef HAVE_CONFIG_H
21# include "config.h"
22#endif
23
24#include <errno.h>
25#include <stdio.h>
26#include <stddef.h>
27
28#include "c-ctype.h"
29#include "message.h"
30#include "xgettext.h"
31#include "x-rst.h"
32#include "error.h"
33#include "error-progname.h"
34#include "xalloc.h"
35#include "exit.h"
36#include "gettext.h"
37
38#define _(s) gettext(s)
39
40/* RST stands for Resource String Table.
41
42   An RST file consists of several string definitions.  A string definition
43   starts at the beginning of a line and looks like this:
44       ModuleName.ConstName=StringExpression
45   A StringExpression consists of string pieces of the form 'xyz',
46   single characters of the form #nnn (decimal integer), and +
47   at the end of the line to designate continuation on the next line.
48   String definitions can be separated by blank lines or comment lines
49   beginning with '#'.
50
51   This backend attempts to be functionally equivalent to the 'rstconv'
52   program, part of the Free Pascal run time library, written by
53   Sebastian Guenther.  Except that the locations are output as
54   "ModuleName.ConstName", not "ModuleName:ConstName".
55 */
56
57void
58extract_rst (FILE *f,
59	     const char *real_filename, const char *logical_filename,
60	     flag_context_list_table_ty *flag_table,
61	     msgdomain_list_ty *mdlp)
62{
63  static char *buffer;
64  static int bufmax;
65  message_list_ty *mlp = mdlp->item[0]->messages;
66  int line_number;
67
68  line_number = 1;
69  for (;;)
70    {
71      int c;
72      int bufpos;
73      char *location;
74      char *msgid;
75      lex_pos_ty pos;
76
77      c = getc (f);
78      if (c == EOF)
79	break;
80
81      /* Ignore blank line.  */
82      if (c == '\n')
83	{
84	  line_number++;
85	  continue;
86	}
87
88      /* Ignore comment line.  */
89      if (c == '#')
90	{
91	  do
92	    c = getc (f);
93	  while (c != EOF && c != '\n');
94	  if (c == EOF)
95	    break;
96	  line_number++;
97	  continue;
98	}
99
100      /* Read ModuleName.ConstName.  */
101      bufpos = 0;
102      for (;;)
103	{
104	  if (c == EOF || c == '\n')
105	    {
106	      error_with_progname = false;
107	      error (EXIT_FAILURE, 0, _("%s:%d: invalid string definition"),
108		     logical_filename, line_number);
109	      error_with_progname = true;
110	    }
111	  if (bufpos >= bufmax)
112	    {
113	      bufmax = 2 * bufmax + 10;
114	      buffer = xrealloc (buffer, bufmax);
115	    }
116	  if (c == '=')
117	    break;
118	  buffer[bufpos++] = c;
119	  c = getc (f);
120	  if (c == EOF && ferror (f))
121	    goto bomb;
122	}
123      buffer[bufpos] = '\0';
124      location = xstrdup (buffer);
125
126      /* Read StringExpression.  */
127      bufpos = 0;
128      for (;;)
129	{
130	  c = getc (f);
131	  if (c == EOF)
132	    break;
133	  else if (c == '\n')
134	    {
135	      line_number++;
136	      break;
137	    }
138	  else if (c == '\'')
139	    {
140	      for (;;)
141		{
142		  c = getc (f);
143		  /* Embedded single quotes like 'abc''def' don't occur.
144		     See fpc-1.0.4/compiler/cresstr.pas.  */
145		  if (c == EOF || c == '\n' || c == '\'')
146		    break;
147		  if (bufpos >= bufmax)
148		    {
149		      bufmax = 2 * bufmax + 10;
150		      buffer = xrealloc (buffer, bufmax);
151		    }
152		  buffer[bufpos++] = c;
153		}
154	      if (c == EOF)
155		break;
156	      else if (c == '\n')
157		{
158		  line_number++;
159		  break;
160		}
161	    }
162	  else if (c == '#')
163	    {
164	      int n;
165	      c = getc (f);
166	      if (c == EOF && ferror (f))
167		goto bomb;
168	      if (c == EOF || !c_isdigit (c))
169		{
170		  error_with_progname = false;
171		  error (EXIT_FAILURE, 0, _("%s:%d: missing number after #"),
172			 logical_filename, line_number);
173		  error_with_progname = true;
174		}
175	      n = (c - '0');
176	      for (;;)
177		{
178		  c = getc (f);
179		  if (c == EOF || !c_isdigit (c))
180		    break;
181		  n = n * 10 + (c - '0');
182		}
183	      if (bufpos >= bufmax)
184		{
185		  bufmax = 2 * bufmax + 10;
186		  buffer = xrealloc (buffer, bufmax);
187		}
188	      buffer[bufpos++] = (unsigned char) n;
189	      if (c == EOF)
190		break;
191	      ungetc (c, f);
192	    }
193	  else if (c == '+')
194	    {
195	      c = getc (f);
196	      if (c == EOF)
197		break;
198	      if (c == '\n')
199		line_number++;
200	      else
201		ungetc (c, f);
202	    }
203	  else
204	    {
205	      error_with_progname = false;
206	      error (EXIT_FAILURE, 0, _("%s:%d: invalid string expression"),
207		     logical_filename, line_number);
208	      error_with_progname = true;
209	    }
210	}
211      if (bufpos >= bufmax)
212	{
213	  bufmax = 2 * bufmax + 10;
214	  buffer = xrealloc (buffer, bufmax);
215	}
216      buffer[bufpos] = '\0';
217      msgid = xstrdup (buffer);
218
219      pos.file_name = location;
220      pos.line_number = (size_t)(-1);
221
222      remember_a_message (mlp, NULL, msgid, null_context, &pos, NULL);
223
224      /* Here c is the last read character: EOF or '\n'.  */
225      if (c == EOF)
226	break;
227    }
228
229  if (ferror (f))
230    {
231    bomb:
232      error (EXIT_FAILURE, errno, _("error while reading \"%s\""),
233	     real_filename);
234    }
235}
236