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