Make ProgramTypeTable related TypeInfo infrastructure const-correct.
[kdbg.git] / kdbg / typetable.cpp
blob65b25995c8a38549df67350e594a68a6cd37a283
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() :
56 m_printQStringDataCmd(0)
58 m_typeDict.setAutoDelete(true);
61 TypeTable::~TypeTable()
63 delete[] m_printQStringDataCmd;
64 while (!m_templates.empty()) {
65 delete m_templates.begin()->second;
66 m_templates.erase(m_templates.begin());
71 static const char TypeTableGroup[] = "Type Table";
72 static const char LibDisplayName[] = "LibDisplayName";
73 static const char ShlibRE[] = "ShlibRE";
74 static const char EnableBuiltin[] = "EnableBuiltin";
75 static const char PrintQStringCmd[] = "PrintQStringCmd";
76 static const char TypesEntryFmt[] = "Types%d";
77 static const char DisplayEntry[] = "Display";
78 static const char AliasEntry[] = "Alias";
79 static const char TemplateEntry[] = "Template";
80 static const char ExprEntryFmt[] = "Expr%d";
81 static const char FunctionGuardEntryFmt[] = "FunctionGuard%d";
84 void TypeTable::loadFromFile(const QString& fileName)
86 TRACE("reading file " + fileName);
87 KConfig confFile(fileName, KConfig::SimpleConfig);
90 * Read library name and properties.
92 KConfigGroup cf = confFile.group(TypeTableGroup);
93 m_displayName = cf.readEntry(LibDisplayName);
94 if (m_displayName.isEmpty()) {
95 // use file name instead
96 QFileInfo fi(fileName);
97 m_displayName = fi.baseName(true);
100 m_shlibNameRE = QRegExp(cf.readEntry(ShlibRE));
101 m_enabledBuiltins = cf.readEntry(EnableBuiltin, QStringList());
103 QString printQString = cf.readEntry(PrintQStringCmd);
104 const char* ascii = printQString.ascii();
105 if (ascii == 0)
106 ascii = "";
107 m_printQStringDataCmd = new char[strlen(ascii)+1];
108 strcpy(m_printQStringDataCmd, ascii);
111 * Get the types. We search for entries of kind Types1, Types2, etc.
112 * because a single entry Types could get rather long for large
113 * libraries.
115 QString typesEntry;
116 for (int i = 1; ; i++) {
117 // next bunch of types
118 KConfigGroup cf = confFile.group(TypeTableGroup);
119 typesEntry.sprintf(TypesEntryFmt, i);
120 if (!cf.hasKey(typesEntry))
121 break;
123 QStringList typeNames = cf.readEntry(typesEntry, QStringList());
125 // now read them
126 QString alias;
127 for (QStringList::iterator it = typeNames.begin(); it != typeNames.end(); ++it)
129 KConfigGroup cf = confFile.group(*it);
130 // check if this is an alias
131 alias = cf.readEntry(AliasEntry);
132 if (alias.isEmpty()) {
133 readType(cf, *it);
134 } else {
135 // look up the alias type and insert it
136 TypeInfo* info = m_typeDict[alias];
137 if (info == 0) {
138 TRACE(*it + ": alias " + alias + " not found");
139 } else {
140 m_aliasDict.insert(std::make_pair(*it, info));
141 TRACE(*it + ": alias " + alias);
145 } // for all Types%d
148 void TypeTable::readType(const KConfigGroup& cf, const QString& type)
150 // the display string
151 QString expr = cf.readEntry(DisplayEntry);
153 TypeInfo* info = new TypeInfo(expr);
154 if (info->m_numExprs == 0) {
155 TRACE("bogus type " + type + ": no %% in Display: " + expr);
156 delete info;
157 return;
160 info->m_templatePattern = cf.readEntry(TemplateEntry);
162 // Expr1, Expr2, etc...
163 QString exprEntry;
164 QString funcGuardEntry;
165 for (int j = 0; j < info->m_numExprs; j++) {
166 exprEntry.sprintf(ExprEntryFmt, j+1);
167 expr = cf.readEntry(exprEntry);
168 info->m_exprStrings[j] = expr;
170 funcGuardEntry.sprintf(FunctionGuardEntryFmt, j+1);
171 expr = cf.readEntry(funcGuardEntry);
172 info->m_guardStrings[j] = expr;
175 // add the new type
176 if (info->m_templatePattern.find('<') < 0)
177 m_typeDict.insert(type, info);
178 else
179 m_templates[type] = info;
180 TRACE(type + QString().sprintf(": %d exprs", info->m_numExprs));
183 void TypeTable::copyTypes(TypeInfoRefMap& dict)
185 for (Q3DictIterator<TypeInfo> it = m_typeDict; it != 0; ++it) {
186 dict.insert(std::make_pair(it.currentKey(), it));
188 std::copy(m_aliasDict.begin(), m_aliasDict.end(),
189 std::inserter(dict, dict.begin()));
192 bool TypeTable::isEnabledBuiltin(const QString& feature) const
194 return m_enabledBuiltins.find(feature) != m_enabledBuiltins.end();
197 TypeInfo::TypeInfo(const QString& displayString)
199 // decompose the input into the parts
200 int i = 0;
201 int startIdx = 0;
202 int idx;
203 while (i < typeInfoMaxExpr &&
204 (idx = displayString.find('%', startIdx)) >= 0)
206 m_displayString[i] = displayString.mid(startIdx, idx-startIdx);
207 startIdx = idx+1;
208 i++;
210 m_numExprs = i;
212 * Remaining string; note that there's one more display string than
213 * sub-expressions.
215 m_displayString[i] = displayString.right(displayString.length()-startIdx);
218 TypeInfo::~TypeInfo()
223 ProgramTypeTable::ProgramTypeTable() :
224 m_parseQt2QStrings(false),
225 m_QCharIsShort(false),
226 m_printQStringDataCmd(0)
230 ProgramTypeTable::~ProgramTypeTable()
234 void ProgramTypeTable::loadTypeTable(TypeTable* table)
236 table->copyTypes(m_types);
238 // add templates
239 const TypeTable::TypeMap& t = table->templates();
240 std::transform(t.begin(), t.end(),
241 std::inserter(m_templates, m_templates.begin()),
242 std::ptr_fun(template2Info));
244 // check whether to enable builtin QString support
245 if (!m_parseQt2QStrings) {
246 m_parseQt2QStrings = table->isEnabledBuiltin("QString::Data");
248 if (!m_QCharIsShort) {
249 m_QCharIsShort = table->isEnabledBuiltin("QCharIsShort");
251 if (!m_printQStringDataCmd && *table->printQStringDataCmd()) {
252 m_printQStringDataCmd = table->printQStringDataCmd();
256 ProgramTypeTable::TemplateMap::value_type
257 ProgramTypeTable::template2Info(const TypeTable::TypeMap::value_type& tt)
259 QStringList args = splitTemplateArgs(tt.second->m_templatePattern);
261 TemplateMap::value_type result(args.front(), TemplateInfo());
262 result.second.type = tt.second;
263 args.pop_front();
264 result.second.templateArgs = args;
265 return result;
269 * Splits the name \a t into the template name and its arguments.
270 * The first entry of the returned list is the template name, the remaining
271 * entries are the arguments.
273 QStringList ProgramTypeTable::splitTemplateArgs(const QString& t)
275 QStringList result;
276 result.push_back(t);
278 int i = t.find('<');
279 if (i < 0)
280 return result;
282 // split off the template name
283 result.front().truncate(i);
285 i++; // skip '<'
286 // look for the next comma or the closing '>', skipping nested '<>'
287 int nest = 0;
288 int start = i;
289 for (; i < t.length() && nest >= 0; i++)
291 if (t[i] == '<')
292 nest++;
293 else if (t[i] == '>')
294 nest--;
295 else if (nest == 0 && t[i] == ',') {
296 // found end of argument
297 QString arg = t.mid(start, i-start);
298 result.push_back(arg);
299 start = i+1; // skip ','
302 // accept the template only if the closing '>' is the last character
303 if (nest < 0 && i == t.length()) {
304 QString arg = t.mid(start, i-start-1);
305 result.push_back(arg);
306 } else {
307 result.clear();
308 result.push_back(t);
310 return result;
313 const TypeInfo* ProgramTypeTable::lookup(QString type)
316 * Registered aliases contain the complete template parameter list.
317 * Check for an alias first so that this case is out of the way.
319 if (const TypeInfo* result = m_aliasDict[type])
320 return result;
323 * Check for a normal type. Even if type is a template instance,
324 * it could have been registered as a normal type instead of a pattern.
326 if (const TypeInfo* result = m_types[type])
327 return result;
330 * The hard part: Look up a template.
332 QStringList parts = splitTemplateArgs(type);
333 if (parts.size() == 1)
334 return 0; // not a template
336 // We can have several patterns for the same template name.
337 std::pair<TemplateMap::const_iterator, TemplateMap::const_iterator> range =
338 m_templates.equal_range(parts.front());
339 // We pick the one that has the wildcards in the later parameters.
340 unsigned minPenalty = ~0U;
341 const TypeInfo* result = 0;
342 parts.pop_front();
344 for (TemplateMap::const_iterator i = range.first; i != range.second; ++i)
346 const QStringList& pat = i->second.templateArgs;
347 if (parts.size() < pat.size())
348 continue; // too few arguments
350 // a "*" in the last position of the pattern matches all arguments
351 // at the end of the template's arguments
352 if (parts.size() > pat.size() && pat.back() != "*")
353 continue; // too many arguments and no wildcard
355 QStringList::const_iterator t = parts.begin();
356 QStringList::const_iterator p = pat.begin();
357 unsigned accumPenalty = 0;
358 bool equal = true;
359 unsigned penalty = ~(~0U>>1); // 1 in the leading bit
360 while (equal && p != pat.end())
362 if (*p == "*")
363 accumPenalty |= penalty; // penalize wildcards
364 else
365 equal = *p == *t;
366 ++p, ++t, penalty >>= 1;
368 if (equal)
370 if (accumPenalty == 0)
371 return i->second.type;
372 if (accumPenalty < minPenalty) {
373 result = i->second.type;
374 minPenalty = accumPenalty;
378 return result;
381 void ProgramTypeTable::registerAlias(const QString& name, const TypeInfo* type)
383 ASSERT(lookup(name) == 0 || lookup(name) == type);
384 m_aliasDict.insert(std::make_pair(name, type));
387 void ProgramTypeTable::loadLibTypes(const QStringList& libs)
389 for (QStringList::const_iterator it = libs.begin(); it != libs.end(); ++it)
391 // look up the library
392 for (std::list<TypeTable>::iterator t = typeTables.begin(); t != typeTables.end(); ++t)
394 if (t->matchFileName(*it))
396 TRACE("adding types for " + *it);
397 loadTypeTable(&*t);