2
* Parser for debian database files
4
* Copyright (C) 2003 Enrico Zini <enrico@debian.org>
6
* This library is free software; you can redistribute it and/or
7
* modify it under the terms of the GNU Lesser General Public
8
* License as published by the Free Software Foundation; either
9
* version 2.1 of the License, or (at your option) any later version.
11
* This library 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 GNU
14
* Lesser General Public License for more details.
16
* You should have received a copy of the GNU Lesser General Public
17
* License along with this library; if not, write to the Free Software
18
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21
#include "debdbparser.h"
27
using namespace Tagcoll;
28
using namespace aptFront;
29
using namespace utils;
31
// Eat spaces and empty lines
32
// Returns the number of '\n' encountered
33
int DebDBParser::eatSpacesAndEmptyLines() throw (ParserException)
37
while ((c = in.nextChar()) != ParserInput::Eof && (isblank(c) || c == '\n'))
46
if (c == ParserInput::Eof)
54
// Get the ^([A-Za-z0-9]+) field name
55
std::string DebDBParser::getFieldName() throw (ParserException)
58
throw ParserException(in, "field must start at the beginning of the line");
63
while ((c = in.nextChar()) != ParserInput::Eof && (isalnum(c) || c == '-'))
66
if (c == ParserInput::Eof)
70
throw ParserException(in, "field is truncated at end of file. Last line begins with: \"" + res + "\n");
77
// Eat the \s*: characters that divide the field name and the field
79
void DebDBParser::eatFieldSep() throw (ParserException)
83
while ((c = in.nextChar()) != ParserInput::Eof && isblank(c))
88
if (c == ParserInput::Eof)
91
throw ParserException(in, "field is truncated at end of file");
93
throw ParserException(in, string("invalid character `") + (char)c + "' expecting `:'");
98
// Get the \s*(.+?)\s*\n of a body line
99
void DebDBParser::appendFieldBody(string& body) throw (ParserException)
103
// Skip leading spaces
104
while ((c = in.nextChar()) != ParserInput::Eof && isblank(c))
108
for ( ; c != ParserInput::Eof && c != '\n'; c = in.nextChar())
111
// Delete trailing spaces
112
unsigned int end = body.find_last_not_of(" \t");
113
if (end != string::npos)
114
body.resize(end + 1);
116
if (c == ParserInput::Eof)
126
DebDBParser::DebDBParser(ParserInput& input) throw (ParserException) :
127
in(input), isBOL(true), isEOF(false)
129
// Go at the start of the next record
130
eatSpacesAndEmptyLines();
134
// Read a record and positions itself at the start of the next one
135
// Returns false when there are no more records available
136
bool DebDBParser::nextRecord(Record& rec) throw (ParserException)
145
// Read the field name
146
string field = getFieldName();
149
//fprintf(stderr, "Got field: %.*s\n", field.size(), field.data());
154
// Read the first line of the field body
155
appendFieldBody(body);
156
//fprintf(stderr, "Got body: %.*s\n", body.size(), body.data());
158
// Read the continuation lines of field body
159
while ((n = eatSpacesAndEmptyLines()) == 0 && ! isBOL)
163
size_t start_size = body.size();
165
appendFieldBody(body);
167
// Check for dot-only lines to be changed to empty lines
168
if (body.size() - start_size == 1 && body[body.size() - 1] == '.')
169
body.resize(body.size() - 1);
171
//fprintf(stderr, "Appended body: %.*s\n", body.size(), body.data());
173
//fprintf(stderr, "Trailing newlines: %d\n", n);
176
rec.insert(pair<string,string>(field, body));
177
} while (!isEOF && !n);
183
void State::read(const char* file)
190
while (p.nextRecord(rec))
192
//fprintf(stderr, "Got record:\n");
193
//for (record::const_iterator i = rec.begin(); i != rec.end(); i++)
194
//fprintf(stderr, "\t%.*s: %.*s\n", i->first.size(), i->first.data(), i->second.size(), i->second.data());
199
record::const_iterator i = rec.find("Name");
201
throw ParserException(file, p.getLine(),
202
"No Name: field found in record %d", rnum);
203
if (find(i->second) != end())
204
throw ParserException(file, p.getLine(),
205
"Duplicate record %d for variable %.*s", rnum,
206
(int)i->second.size(), i->second.data());
207
const string& name = i->second;
209
// Variable description
210
i = rec.find("Description");
212
throw ParserException(file, p.getLine(),
213
"No Description: field found in record %d for %.*s",
214
rnum, (int)name.size(), name.data());
215
const string& desc = i->second;
217
// Variable type (bool if omitted)
218
Variable::Type type = Variable::vBOOL;
219
i = rec.find("Type");
221
if (i->second == "enum")
222
type = Variable::vENUM;
223
else if (i->second != "bool")
224
throw ParserException(file, p.getLine(),
225
"Invalid type %.*s for variable %.*s",
226
(int)i->second.size(), i->second.data(),
227
(int)name.size(), name.data());
232
case Variable::vBOOL:
234
// Default value (defaults to 'false')
235
i = rec.find("Default");
238
if (i->second == "true")
240
else if (i->second == "false")
243
throw ParserException(file, p.getLine(),
244
"Invalid value `%.*s' for Default: field in"
245
" record %d for variable %.*s",
246
(int)i->second.size(), i->second.data(), rnum,
247
(int)name.size(), name.data());
248
var = new BoolVariable(name, desc, val);
251
case Variable::vENUM:
253
// Domain for the enum: comma-separated list of
254
// [^ ,]+ or "<string with \<char> escapes"
255
record::iterator i = rec.find("Domain");
257
throw ParserException(file, p.getLine(),
258
"No Domain: field found for enum `%.*s'"
259
" in record %d", (int)name.size(), name.data(),
261
string& domainstr = i->second;
264
// Parse the domain enumeration
265
parse_enum_domain(domainstr, domain, file, p.getLine());
267
// Default value (mandatory for enums)
268
i = rec.find("Default");
270
throw ParserException(file, p.getLine(),
271
"No Default: field found in record %d for enum `%.*s'",
272
rnum, (int)name.size(), name.data());
273
const string& val = i->second;
275
var = new EnumVariable(name, desc, val, domain);
280
insert(pair<string, Variable*>(name, var));
289
// vim:set ts=4 sw=4: