KDbg 2.5.6.
[kdbg.git] / kdbg / typetable.cpp
blobb7f74c63b47f92f57b3d7129673998856cb2d5b6
1 /*
2 * Copyright Johannes Sixt
3 * This file is licensed under the GNU General Public License Version 2.
4 * See the file COPYING in the toplevel directory of the source directory.
5 */
7 #include "typetable.h"
8 #include <QFileInfo>
9 #include <kglobal.h>
10 #include <kstandarddirs.h>
11 #include <kconfig.h>
12 #include <kconfiggroup.h>
13 #include <list>
14 #include <algorithm>
15 #include <iterator>
16 #include "mydebug.h"
18 //! the TypeTables of all known libraries
19 static std::list<TypeTable> typeTables;
20 bool typeTablesInited = false;
23 //! an indentifier for wchar_t
24 TypeInfo TypeInfo::m_wchartType("");
25 //! the unknown type
26 TypeInfo TypeInfo::m_unknownType("");
29 void TypeTable::initTypeLibraries()
31 if (!typeTablesInited) {
32 TypeTable::loadTypeTables();
36 void TypeTable::loadTypeTables()
38 typeTablesInited = true;
40 const QStringList files = KGlobal::dirs()->findAllResources("types", "*.kdbgtt",
41 KStandardDirs::NoDuplicates);
43 if (files.isEmpty()) {
44 TRACE("no type tables found");
45 return;
48 for (QStringList::ConstIterator p = files.begin(); p != files.end(); ++p) {
49 typeTables.push_back(TypeTable());
50 typeTables.back().loadFromFile(*p);
55 TypeTable::TypeTable()
59 TypeTable::~TypeTable()
64 static const char TypeTableGroup[] = "Type Table";
65 static const char LibDisplayName[] = "LibDisplayName";
66 static const char ShlibRE[] = "ShlibRE";
67 static const char EnableBuiltin[] = "EnableBuiltin";
68 static const char PrintQStringCmd[] = "PrintQStringCmd";
69 static const char TypesEntryFmt[] = "Types%d";
70 static const char DisplayEntry[] = "Display";
71 static const char AliasEntry[] = "Alias";
72 static const char TemplateEntry[] = "Template";
73 static const char ExprEntryFmt[] = "Expr%d";
74 static const char FunctionGuardEntryFmt[] = "FunctionGuard%d";
77 void TypeTable::loadFromFile(const QString& fileName)
79 TRACE("reading file " + fileName);
80 KConfig confFile(fileName, KConfig::SimpleConfig);
83 * Read library name and properties.
85 KConfigGroup cf = confFile.group(TypeTableGroup);
86 m_displayName = cf.readEntry(LibDisplayName);
87 if (m_displayName.isEmpty()) {
88 // use file name instead
89 QFileInfo fi(fileName);
90 m_displayName = fi.completeBaseName();
93 m_shlibNameRE = QRegExp(cf.readEntry(ShlibRE));
94 m_enabledBuiltins = cf.readEntry(EnableBuiltin, QStringList());
96 QString printQString = cf.readEntry(PrintQStringCmd);
97 m_printQStringDataCmd = printQString.toAscii();
100 * Get the types. We search for entries of kind Types1, Types2, etc.
101 * because a single entry Types could get rather long for large
102 * libraries.
104 QString typesEntry;
105 for (int i = 1; ; i++) {
106 // next bunch of types
107 KConfigGroup cf = confFile.group(TypeTableGroup);
108 typesEntry.sprintf(TypesEntryFmt, i);
109 if (!cf.hasKey(typesEntry))
110 break;
112 QStringList typeNames = cf.readEntry(typesEntry, QStringList());
114 // now read them
115 QString alias;
116 for (QStringList::iterator it = typeNames.begin(); it != typeNames.end(); ++it)
118 KConfigGroup cf = confFile.group(*it);
119 // check if this is an alias
120 alias = cf.readEntry(AliasEntry);
121 if (alias.isEmpty()) {
122 readType(cf, *it);
123 } else {
124 // look up the alias type and insert it
125 TypeInfoMap::iterator i = m_typeDict.find(alias);
126 if (i == m_typeDict.end()) {
127 TRACE(*it + ": alias " + alias + " not found");
128 } else {
129 m_aliasDict.insert(std::make_pair(*it, &i->second));
130 TRACE(*it + ": alias " + alias);
134 } // for all Types%d
137 void TypeTable::readType(const KConfigGroup& cf, const QString& type)
139 // the display string
140 QString expr = cf.readEntry(DisplayEntry);
142 TypeInfo info(expr);
143 if (info.m_numExprs == 0) {
144 TRACE("bogus type " + type + ": no %% in Display: " + expr);
145 return;
148 info.m_templatePattern = cf.readEntry(TemplateEntry);
150 // Expr1, Expr2, etc...
151 QString exprEntry;
152 QString funcGuardEntry;
153 for (int j = 0; j < info.m_numExprs; j++)
155 exprEntry.sprintf(ExprEntryFmt, j+1);
156 expr = cf.readEntry(exprEntry);
157 info.m_exprStrings[j] = expr;
159 funcGuardEntry.sprintf(FunctionGuardEntryFmt, j+1);
160 expr = cf.readEntry(funcGuardEntry);
161 info.m_guardStrings[j] = expr;
164 // add the new type
165 if (info.m_templatePattern.indexOf('<') < 0)
166 m_typeDict.insert(std::make_pair(type, info));
167 else
168 m_templates.insert(std::make_pair(type, info));
169 TRACE(type + QString().sprintf(": %d exprs", info.m_numExprs));
172 void TypeTable::copyTypes(TypeInfoRefMap& dict)
174 for (TypeInfoMap::iterator i = m_typeDict.begin(); i != m_typeDict.end(); ++i) {
175 dict.insert(std::make_pair(i->first, &i->second));
177 std::copy(m_aliasDict.begin(), m_aliasDict.end(),
178 std::inserter(dict, dict.begin()));
181 bool TypeTable::isEnabledBuiltin(const QString& feature) const
183 return m_enabledBuiltins.indexOf(feature) >= 0;
186 TypeInfo::TypeInfo(const QString& displayString)
188 // decompose the input into the parts
189 int i = 0;
190 int startIdx = 0;
191 int idx;
192 while (i < typeInfoMaxExpr &&
193 (idx = displayString.indexOf('%', startIdx)) >= 0)
195 m_displayString[i] = displayString.mid(startIdx, idx-startIdx);
196 startIdx = idx+1;
197 i++;
199 m_numExprs = i;
201 * Remaining string; note that there's one more display string than
202 * sub-expressions.
204 m_displayString[i] = displayString.right(displayString.length()-startIdx);
207 TypeInfo::~TypeInfo()
212 ProgramTypeTable::ProgramTypeTable() :
213 m_parseQt2QStrings(false),
214 m_QCharIsShort(false),
215 m_printQStringDataCmd(0)
219 ProgramTypeTable::~ProgramTypeTable()
223 void ProgramTypeTable::loadTypeTable(TypeTable* table)
225 table->copyTypes(m_types);
227 // add templates
228 const TypeTable::TypeInfoMap& t = table->templates();
229 std::transform(t.begin(), t.end(),
230 std::inserter(m_templates, m_templates.begin()),
231 std::ptr_fun(template2Info));
233 // check whether to enable builtin QString support
234 if (!m_parseQt2QStrings) {
235 m_parseQt2QStrings = table->isEnabledBuiltin("QString::Data");
237 if (!m_QCharIsShort) {
238 m_QCharIsShort = table->isEnabledBuiltin("QCharIsShort");
240 if (m_printQStringDataCmd.isEmpty()) {
241 m_printQStringDataCmd = table->printQStringDataCmd();
245 ProgramTypeTable::TemplateMap::value_type
246 ProgramTypeTable::template2Info(const TypeTable::TypeInfoMap::value_type& tt)
248 QStringList args = splitTemplateArgs(tt.second.m_templatePattern);
250 TemplateMap::value_type result(args.front(), TemplateInfo());
251 result.second.type = &tt.second;
252 args.pop_front();
253 result.second.templateArgs = args;
254 return result;
258 * Splits the name \a t into the template name and its arguments.
259 * The first entry of the returned list is the template name, the remaining
260 * entries are the arguments.
262 QStringList ProgramTypeTable::splitTemplateArgs(const QString& t)
264 QStringList result;
265 result.push_back(t);
267 int i = t.indexOf('<');
268 if (i < 0)
269 return result;
271 // split off the template name
272 result.front().truncate(i);
274 i++; // skip '<'
275 // look for the next comma or the closing '>', skipping nested '<>'
276 int nest = 0;
277 int start = i;
278 for (; i < t.length() && nest >= 0; i++)
280 if (t[i] == '<')
281 nest++;
282 else if (t[i] == '>')
283 nest--;
284 else if (nest == 0 && t[i] == ',') {
285 // found end of argument
286 QString arg = t.mid(start, i-start);
287 result.push_back(arg);
288 start = i+1; // skip ','
291 // accept the template only if the closing '>' is the last character
292 if (nest < 0 && i == t.length()) {
293 QString arg = t.mid(start, i-start-1);
294 result.push_back(arg);
295 } else {
296 result.clear();
297 result.push_back(t);
299 return result;
302 const TypeInfo* ProgramTypeTable::lookup(QString type)
305 * Registered aliases contain the complete template parameter list.
306 * Check for an alias first so that this case is out of the way.
308 if (const TypeInfo* result = m_aliasDict[type])
309 return result;
312 * Check for a normal type. Even if type is a template instance,
313 * it could have been registered as a normal type instead of a pattern.
315 if (const TypeInfo* result = m_types[type])
316 return result;
319 * The hard part: Look up a template.
321 QStringList parts = splitTemplateArgs(type);
322 if (parts.size() == 1)
323 return 0; // not a template
325 // We can have several patterns for the same template name.
326 std::pair<TemplateMap::const_iterator, TemplateMap::const_iterator> range =
327 m_templates.equal_range(parts.front());
328 // We pick the one that has the wildcards in the later parameters.
329 unsigned minPenalty = ~0U;
330 const TypeInfo* result = 0;
331 parts.pop_front();
333 for (TemplateMap::const_iterator i = range.first; i != range.second; ++i)
335 const QStringList& pat = i->second.templateArgs;
336 if (parts.size() < pat.size())
337 continue; // too few arguments
339 // a "*" in the last position of the pattern matches all arguments
340 // at the end of the template's arguments
341 if (parts.size() > pat.size() && pat.back() != "*")
342 continue; // too many arguments and no wildcard
344 QStringList::const_iterator t = parts.begin();
345 QStringList::const_iterator p = pat.begin();
346 unsigned accumPenalty = 0;
347 bool equal = true;
348 unsigned penalty = ~(~0U>>1); // 1 in the leading bit
349 while (equal && p != pat.end())
351 if (*p == "*")
352 accumPenalty |= penalty; // penalize wildcards
353 else
354 equal = *p == *t;
355 ++p, ++t, penalty >>= 1;
357 if (equal)
359 if (accumPenalty == 0)
360 return i->second.type;
361 if (accumPenalty < minPenalty) {
362 result = i->second.type;
363 minPenalty = accumPenalty;
367 return result;
370 void ProgramTypeTable::registerAlias(const QString& name, const TypeInfo* type)
372 ASSERT(lookup(name) == 0 || lookup(name) == type);
373 m_aliasDict.insert(std::make_pair(name, type));
376 void ProgramTypeTable::loadLibTypes(const QStringList& libs)
378 for (QStringList::const_iterator it = libs.begin(); it != libs.end(); ++it)
380 // look up the library
381 for (std::list<TypeTable>::iterator t = typeTables.begin(); t != typeTables.end(); ++t)
383 if (t->matchFileName(*it))
385 TRACE("adding types for " + *it);
386 loadTypeTable(&*t);