Convert parseSharedLibs() from QStrList to QStringList.
[kdbg.git] / kdbg / typetable.cpp
blob3730f631d86996c7c16060d5d8a65b32e25f1815
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 <qdir.h>
8 #include <qptrlist.h>
9 #include <kglobal.h>
10 #include <kstandarddirs.h>
11 #include <ksimpleconfig.h>
12 #include <list>
13 #include <algorithm>
14 #include <iterator>
15 #ifdef HAVE_CONFIG_H
16 #include "config.h"
17 #endif
18 #include "typetable.h"
19 #include "mydebug.h"
21 //! the TypeTables of all known libraries
22 static std::list<TypeTable> typeTables;
23 bool typeTablesInited = false;
26 //! an indentifier for wchar_t
27 TypeInfo TypeInfo::m_wchartType("");
28 //! the unknown type
29 TypeInfo TypeInfo::m_unknownType("");
32 void TypeTable::initTypeLibraries()
34 if (!typeTablesInited) {
35 TypeTable::loadTypeTables();
39 void TypeTable::loadTypeTables()
41 typeTablesInited = true;
43 const QStringList files = KGlobal::dirs()->findAllResources("types", "*.kdbgtt",
44 false, true);
46 if (files.isEmpty()) {
47 TRACE("no type tables found");
48 return;
51 for (QValueListConstIterator<QString> p = files.begin(); p != files.end(); ++p) {
52 typeTables.push_back(TypeTable());
53 typeTables.back().loadFromFile(*p);
58 TypeTable::TypeTable() :
59 m_printQStringDataCmd(0)
61 m_typeDict.setAutoDelete(true);
62 // aliasDict keeps only pointers to items into typeDict
63 m_aliasDict.setAutoDelete(false);
66 TypeTable::~TypeTable()
68 delete[] m_printQStringDataCmd;
69 while (!m_templates.empty()) {
70 delete m_templates.begin()->second;
71 m_templates.erase(m_templates.begin());
76 static const char TypeTableGroup[] = "Type Table";
77 static const char LibDisplayName[] = "LibDisplayName";
78 static const char ShlibRE[] = "ShlibRE";
79 static const char EnableBuiltin[] = "EnableBuiltin";
80 static const char PrintQStringCmd[] = "PrintQStringCmd";
81 static const char TypesEntryFmt[] = "Types%d";
82 static const char DisplayEntry[] = "Display";
83 static const char AliasEntry[] = "Alias";
84 static const char TemplateEntry[] = "Template";
85 static const char ExprEntryFmt[] = "Expr%d";
86 static const char FunctionGuardEntryFmt[] = "FunctionGuard%d";
89 void TypeTable::loadFromFile(const QString& fileName)
91 TRACE("reading file " + fileName);
92 KSimpleConfig cf(fileName, true); /* read-only */
95 * Read library name and properties.
97 cf.setGroup(TypeTableGroup);
98 m_displayName = cf.readEntry(LibDisplayName);
99 if (m_displayName.isEmpty()) {
100 // use file name instead
101 QFileInfo fi(fileName);
102 m_displayName = fi.baseName(true);
105 m_shlibNameRE = QRegExp(cf.readEntry(ShlibRE));
106 m_enabledBuiltins = cf.readListEntry(EnableBuiltin);
108 QString printQString = cf.readEntry(PrintQStringCmd);
109 const char* ascii = printQString.ascii();
110 if (ascii == 0)
111 ascii = "";
112 m_printQStringDataCmd = new char[strlen(ascii)+1];
113 strcpy(m_printQStringDataCmd, ascii);
116 * Get the types. We search for entries of kind Types1, Types2, etc.
117 * because a single entry Types could get rather long for large
118 * libraries.
120 QString typesEntry;
121 for (int i = 1; ; i++) {
122 // next bunch of types
123 cf.setGroup(TypeTableGroup);
124 typesEntry.sprintf(TypesEntryFmt, i);
125 if (!cf.hasKey(typesEntry))
126 break;
128 QStringList typeNames = cf.readListEntry(typesEntry, ',');
130 // now read them
131 QString alias;
132 for (QStringList::iterator it = typeNames.begin(); it != typeNames.end(); ++it)
134 cf.setGroup(*it);
135 // check if this is an alias
136 alias = cf.readEntry(AliasEntry);
137 if (alias.isEmpty()) {
138 readType(cf, *it);
139 } else {
140 // look up the alias type and insert it
141 TypeInfo* info = m_typeDict[alias];
142 if (info == 0) {
143 TRACE(*it + ": alias " + alias + " not found");
144 } else {
145 m_aliasDict.insert(alias, info);
146 TRACE(*it + ": alias " + alias);
150 } // for all Types%d
153 void TypeTable::readType(KConfigBase& cf, const QString& type)
155 // the display string
156 QString expr = cf.readEntry(DisplayEntry);
158 TypeInfo* info = new TypeInfo(expr);
159 if (info->m_numExprs == 0) {
160 TRACE("bogus type " + type + ": no %% in Display: " + expr);
161 delete info;
162 return;
165 info->m_templatePattern = cf.readEntry(TemplateEntry);
167 // Expr1, Expr2, etc...
168 QString exprEntry;
169 QString funcGuardEntry;
170 for (int j = 0; j < info->m_numExprs; j++) {
171 exprEntry.sprintf(ExprEntryFmt, j+1);
172 expr = cf.readEntry(exprEntry);
173 info->m_exprStrings[j] = expr;
175 funcGuardEntry.sprintf(FunctionGuardEntryFmt, j+1);
176 expr = cf.readEntry(funcGuardEntry);
177 info->m_guardStrings[j] = expr;
180 // add the new type
181 if (info->m_templatePattern.find('<') < 0)
182 m_typeDict.insert(type, info);
183 else
184 m_templates[type] = info;
185 TRACE(type + QString().sprintf(": %d exprs", info->m_numExprs));
188 void TypeTable::copyTypes(QDict<TypeInfo>& dict)
190 for (QDictIterator<TypeInfo> it = m_typeDict; it != 0; ++it) {
191 dict.insert(it.currentKey(), it);
193 for (QDictIterator<TypeInfo> it = m_aliasDict; it != 0; ++it) {
194 dict.insert(it.currentKey(), it);
198 bool TypeTable::isEnabledBuiltin(const QString& feature) const
200 return m_enabledBuiltins.find(feature) != m_enabledBuiltins.end();
203 TypeInfo::TypeInfo(const QString& displayString)
205 // decompose the input into the parts
206 int i = 0;
207 int startIdx = 0;
208 int idx;
209 while (i < typeInfoMaxExpr &&
210 (idx = displayString.find('%', startIdx)) >= 0)
212 m_displayString[i] = displayString.mid(startIdx, idx-startIdx);
213 startIdx = idx+1;
214 i++;
216 m_numExprs = i;
218 * Remaining string; note that there's one more display string than
219 * sub-expressions.
221 m_displayString[i] = displayString.right(displayString.length()-startIdx);
224 TypeInfo::~TypeInfo()
229 ProgramTypeTable::ProgramTypeTable() :
230 m_parseQt2QStrings(false),
231 m_QCharIsShort(false),
232 m_printQStringDataCmd(0)
234 m_types.setAutoDelete(false); /* paranoia */
235 m_aliasDict.setAutoDelete(false); /* paranoia */
238 ProgramTypeTable::~ProgramTypeTable()
242 void ProgramTypeTable::loadTypeTable(TypeTable* table)
244 table->copyTypes(m_types);
246 // add templates
247 const TypeTable::TypeMap& t = table->templates();
248 std::transform(t.begin(), t.end(),
249 std::inserter(m_templates, m_templates.begin()),
250 std::ptr_fun(template2Info));
252 // check whether to enable builtin QString support
253 if (!m_parseQt2QStrings) {
254 m_parseQt2QStrings = table->isEnabledBuiltin("QString::Data");
256 if (!m_QCharIsShort) {
257 m_QCharIsShort = table->isEnabledBuiltin("QCharIsShort");
259 if (!m_printQStringDataCmd && *table->printQStringDataCmd()) {
260 m_printQStringDataCmd = table->printQStringDataCmd();
264 ProgramTypeTable::TemplateMap::value_type
265 ProgramTypeTable::template2Info(const TypeTable::TypeMap::value_type& tt)
267 QStringList args = splitTemplateArgs(tt.second->m_templatePattern);
269 TemplateMap::value_type result(args.front(), TemplateInfo());
270 result.second.type = tt.second;
271 args.pop_front();
272 result.second.templateArgs = args;
273 return result;
277 * Splits the name \a t into the template name and its arguments.
278 * The first entry of the returned list is the template name, the remaining
279 * entries are the arguments.
281 QStringList ProgramTypeTable::splitTemplateArgs(const QString& t)
283 QStringList result;
284 result.push_back(t);
286 int i = t.find('<');
287 if (i < 0)
288 return result;
290 // split off the template name
291 result.front().truncate(i);
293 i++; // skip '<'
294 // look for the next comma or the closing '>', skipping nested '<>'
295 int nest = 0;
296 int start = i;
297 for (; unsigned(i) < t.length() && nest >= 0; i++)
299 if (t[i] == '<')
300 nest++;
301 else if (t[i] == '>')
302 nest--;
303 else if (nest == 0 && t[i] == ',') {
304 // found end of argument
305 QString arg = t.mid(start, i-start);
306 result.push_back(arg);
307 start = i+1; // skip ','
310 // accept the template only if the closing '>' is the last character
311 if (nest < 0 && unsigned(i) == t.length()) {
312 QString arg = t.mid(start, i-start-1);
313 result.push_back(arg);
314 } else {
315 result.clear();
316 result.push_back(t);
318 return result;
321 TypeInfo* ProgramTypeTable::lookup(QString type)
324 * Registered aliases contain the complete template parameter list.
325 * Check for an alias first so that this case is out of the way.
327 if (TypeInfo* result = m_aliasDict[type])
328 return result;
331 * Check for a normal type. Even if type is a template instance,
332 * it could have been registered as a normal type instead of a pattern.
334 if (TypeInfo* result = m_types[type])
335 return result;
338 * The hard part: Look up a template.
340 QStringList parts = splitTemplateArgs(type);
341 if (parts.size() == 1)
342 return 0; // not a template
344 // We can have several patterns for the same template name.
345 std::pair<TemplateMap::const_iterator, TemplateMap::const_iterator> range =
346 m_templates.equal_range(parts.front());
347 // We pick the one that has the wildcards in the later parameters.
348 unsigned minPenalty = ~0U;
349 TypeInfo* result = 0;
350 parts.pop_front();
352 for (TemplateMap::const_iterator i = range.first; i != range.second; ++i)
354 const QStringList& pat = i->second.templateArgs;
355 if (parts.size() < pat.size())
356 continue; // too few arguments
358 // a "*" in the last position of the pattern matches all arguments
359 // at the end of the template's arguments
360 if (parts.size() > pat.size() && pat.back() != "*")
361 continue; // too many arguments and no wildcard
363 QStringList::const_iterator t = parts.begin();
364 QStringList::const_iterator p = pat.begin();
365 unsigned penalty = 0;
366 bool equal = true;
367 for (int j = 0; equal && p != pat.end(); ++p, ++t, ++j)
369 if (*p == "*")
370 penalty += 1U << j; // penalize wildcards
371 else
372 equal = *p == *t;
374 if (equal)
376 if (penalty == 0)
377 return i->second.type;
378 if (penalty < minPenalty)
379 result = i->second.type;
382 return result;
385 void ProgramTypeTable::registerAlias(const QString& name, TypeInfo* type)
387 ASSERT(lookup(name) == 0 || lookup(name) == type);
388 m_aliasDict.insert(name, type);
391 void ProgramTypeTable::loadLibTypes(const QStringList& libs)
393 for (QStringList::const_iterator it = libs.begin(); it != libs.end(); ++it)
395 // look up the library
396 for (std::list<TypeTable>::iterator t = typeTables.begin(); t != typeTables.end(); ++t)
398 if (t->matchFileName(*it))
400 TRACE("adding types for " + *it);
401 loadTypeTable(&*t);