xref: /netbsd-src/external/gpl2/gettext/dist/gettext-tools/src/x-rst.c (revision 946379e7b37692fc43f68eb0d1c10daa0a7f3b6c)
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 
57 void
extract_rst(FILE * f,const char * real_filename,const char * logical_filename,flag_context_list_table_ty * flag_table,msgdomain_list_ty * mdlp)58 extract_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