Add FUDesc for IprAccess
[gem5.git] / base / inifile.cc
1 /*
2 * Copyright (c) 2001-2004 The Regents of The University of Michigan
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
7 * met: redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer;
9 * redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution;
12 * neither the name of the copyright holders nor the names of its
13 * contributors may be used to endorse or promote products derived from
14 * this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29 #define USE_CPP
30
31 #ifdef USE_CPP
32 #include <sys/signal.h>
33 #include <sys/types.h>
34 #include <sys/wait.h>
35
36 #include <libgen.h>
37 #include <stdio.h>
38 #include <stdlib.h>
39 #include <unistd.h>
40 #endif
41
42 #include <fstream>
43 #include <iostream>
44
45 #include <vector>
46 #include <string>
47
48 #include "base/inifile.hh"
49 #include "base/str.hh"
50
51 using namespace std;
52
53 IniFile::IniFile()
54 {}
55
56 IniFile::~IniFile()
57 {
58 SectionTable::iterator i = table.begin();
59 SectionTable::iterator end = table.end();
60
61 while (i != end) {
62 delete (*i).second;
63 ++i;
64 }
65 }
66
67
68 #ifdef USE_CPP
69 bool
70 IniFile::loadCPP(const string &file, vector<char *> &cppArgs)
71 {
72 // Open the file just to verify that we can. Otherwise if the
73 // file doesn't exist or has bad permissions the user will get
74 // confusing errors from cpp/g++.
75 ifstream tmpf(file.c_str());
76
77 if (!tmpf.is_open())
78 return false;
79
80 tmpf.close();
81
82 char *cfile = strcpy(new char[file.size() + 1], file.c_str());
83 char *dir = dirname(cfile);
84 char *dir_arg = NULL;
85 if (*dir != '.') {
86 string arg = "-I";
87 arg += dir;
88
89 dir_arg = new char[arg.size() + 1];
90 strcpy(dir_arg, arg.c_str());
91 }
92
93 delete [] cfile;
94
95 char tempfile[] = "/tmp/configXXXXXX";
96 int tmp_fd = mkstemp(tempfile);
97
98 int pid = fork();
99
100 if (pid == -1)
101 return false;
102
103 if (pid == 0) {
104 char filename[FILENAME_MAX];
105 string::size_type i = file.copy(filename, sizeof(filename) - 1);
106 filename[i] = '\0';
107
108 int arg_count = cppArgs.size();
109
110 char **args = new char *[arg_count + 20];
111
112 int nextArg = 0;
113 args[nextArg++] = "g++";
114 args[nextArg++] = "-E";
115 args[nextArg++] = "-P";
116 args[nextArg++] = "-nostdinc";
117 args[nextArg++] = "-nostdinc++";
118 args[nextArg++] = "-x";
119 args[nextArg++] = "c++";
120 args[nextArg++] = "-undef";
121
122 for (int i = 0; i < arg_count; i++)
123 args[nextArg++] = cppArgs[i];
124
125 if (dir_arg)
126 args[nextArg++] = dir_arg;
127
128 args[nextArg++] = filename;
129 args[nextArg++] = NULL;
130
131 close(STDOUT_FILENO);
132 if (dup2(tmp_fd, STDOUT_FILENO) == -1)
133 exit(1);
134
135 execvp("g++", args);
136
137 exit(0);
138 }
139
140 int retval;
141 waitpid(pid, &retval, 0);
142
143 delete [] dir_arg;
144
145 // check for normal completion of CPP
146 if (!WIFEXITED(retval) || WEXITSTATUS(retval) != 0)
147 return false;
148
149 close(tmp_fd);
150
151 bool status = false;
152
153 status = load(tempfile);
154
155 unlink(tempfile);
156
157 return status;
158 }
159 #endif
160
161 bool
162 IniFile::load(const string &file)
163 {
164 ifstream f(file.c_str());
165
166 if (!f.is_open())
167 return false;
168
169 return load(f);
170 }
171
172
173 const string &
174 IniFile::Entry::getValue() const
175 {
176 referenced = true;
177 return value;
178 }
179
180
181 void
182 IniFile::Section::addEntry(const std::string &entryName,
183 const std::string &value,
184 bool append)
185 {
186 EntryTable::iterator ei = table.find(entryName);
187
188 if (ei == table.end()) {
189 // new entry
190 table[entryName] = new Entry(value);
191 }
192 else if (append) {
193 // append new reult to old entry
194 ei->second->appendValue(value);
195 }
196 else {
197 // override old entry
198 ei->second->setValue(value);
199 }
200 }
201
202
203 bool
204 IniFile::Section::add(const std::string &assignment)
205 {
206 string::size_type offset = assignment.find('=');
207 if (offset == string::npos) {
208 // no '=' found
209 cerr << "Can't parse .ini line " << assignment << endl;
210 return false;
211 }
212
213 // if "+=" rather than just "=" then append value
214 bool append = (assignment[offset-1] == '+');
215
216 string entryName = assignment.substr(0, append ? offset-1 : offset);
217 string value = assignment.substr(offset + 1);
218
219 eat_white(entryName);
220 eat_white(value);
221
222 addEntry(entryName, value, append);
223 return true;
224 }
225
226
227 IniFile::Entry *
228 IniFile::Section::findEntry(const std::string &entryName) const
229 {
230 referenced = true;
231
232 EntryTable::const_iterator ei = table.find(entryName);
233
234 return (ei == table.end()) ? NULL : ei->second;
235 }
236
237
238 IniFile::Section *
239 IniFile::addSection(const string &sectionName)
240 {
241 SectionTable::iterator i = table.find(sectionName);
242
243 if (i != table.end()) {
244 return i->second;
245 }
246 else {
247 // new entry
248 Section *sec = new Section();
249 table[sectionName] = sec;
250 return sec;
251 }
252 }
253
254
255 IniFile::Section *
256 IniFile::findSection(const string &sectionName) const
257 {
258 SectionTable::const_iterator i = table.find(sectionName);
259
260 return (i == table.end()) ? NULL : i->second;
261 }
262
263
264 // Take string of the form "<section>:<parameter>=<value>" and add to
265 // database. Return true if successful, false if parse error.
266 bool
267 IniFile::add(const string &str)
268 {
269 // find ':'
270 string::size_type offset = str.find(':');
271 if (offset == string::npos) // no ':' found
272 return false;
273
274 string sectionName = str.substr(0, offset);
275 string rest = str.substr(offset + 1);
276
277 eat_white(sectionName);
278 Section *s = addSection(sectionName);
279
280 return s->add(rest);
281 }
282
283 bool
284 IniFile::load(istream &f)
285 {
286 Section *section = NULL;
287
288 while (!f.eof()) {
289 f >> ws; // Eat whitespace
290 if (f.eof()) {
291 break;
292 }
293
294 string line;
295 getline(f, line);
296 if (line.size() == 0)
297 continue;
298
299 eat_end_white(line);
300 int last = line.size() - 1;
301
302 if (line[0] == '[' && line[last] == ']') {
303 string sectionName = line.substr(1, last - 1);
304 eat_white(sectionName);
305 section = addSection(sectionName);
306 continue;
307 }
308
309 if (section == NULL)
310 continue;
311
312 if (!section->add(line))
313 return false;
314 }
315
316 return true;
317 }
318
319 bool
320 IniFile::find(const string &sectionName, const string &entryName,
321 string &value) const
322 {
323 Section *section = findSection(sectionName);
324 if (section == NULL)
325 return false;
326
327 Entry *entry = section->findEntry(entryName);
328 if (entry == NULL)
329 return false;
330
331 value = entry->getValue();
332
333 return true;
334 }
335
336 bool
337 IniFile::sectionExists(const string &sectionName) const
338 {
339 return findSection(sectionName) != NULL;
340 }
341
342
343 bool
344 IniFile::Section::printUnreferenced(const string &sectionName)
345 {
346 bool unref = false;
347 bool search_unref_entries = false;
348 vector<string> unref_ok_entries;
349
350 Entry *entry = findEntry("unref_entries_ok");
351 if (entry != NULL) {
352 tokenize(unref_ok_entries, entry->getValue(), ' ');
353 if (unref_ok_entries.size()) {
354 search_unref_entries = true;
355 }
356 }
357
358 for (EntryTable::iterator ei = table.begin();
359 ei != table.end(); ++ei) {
360 const string &entryName = ei->first;
361 Entry *entry = ei->second;
362
363 if (entryName == "unref_section_ok" ||
364 entryName == "unref_entries_ok")
365 {
366 continue;
367 }
368
369 if (!entry->isReferenced()) {
370 if (search_unref_entries &&
371 (std::find(unref_ok_entries.begin(), unref_ok_entries.end(),
372 entryName) != unref_ok_entries.end()))
373 {
374 continue;
375 }
376
377 cerr << "Parameter " << sectionName << ":" << entryName
378 << " not referenced." << endl;
379 unref = true;
380 }
381 }
382
383 return unref;
384 }
385
386
387 bool
388 IniFile::printUnreferenced()
389 {
390 bool unref = false;
391
392 for (SectionTable::iterator i = table.begin();
393 i != table.end(); ++i) {
394 const string &sectionName = i->first;
395 Section *section = i->second;
396
397 if (!section->isReferenced()) {
398 if (section->findEntry("unref_section_ok") == NULL) {
399 cerr << "Section " << sectionName << " not referenced."
400 << endl;
401 unref = true;
402 }
403 }
404 else {
405 if (section->printUnreferenced(sectionName)) {
406 unref = true;
407 }
408 }
409 }
410
411 return unref;
412 }
413
414
415 void
416 IniFile::Section::dump(const string &sectionName)
417 {
418 for (EntryTable::iterator ei = table.begin();
419 ei != table.end(); ++ei) {
420 cout << sectionName << ": " << (*ei).first << " => "
421 << (*ei).second->getValue() << "\n";
422 }
423 }
424
425 void
426 IniFile::dump()
427 {
428 for (SectionTable::iterator i = table.begin();
429 i != table.end(); ++i) {
430 i->second->dump(i->first);
431 }
432 }