Convert KAboutData and KCmdLineOptions.
[kdbg.git] / kdbg / typetable.cpp
blobbf368ed3a4e1950e0254425fc7beb1041688c265
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 <q3ptrlist.h>
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 "typetable.h"
17 #include "mydebug.h"
19 //! the TypeTables of all known libraries
20 static std::list<TypeTable> typeTables;
21 bool typeTablesInited = false;
24 //! an indentifier for wchar_t
25 TypeInfo TypeInfo::m_wchartType("");
26 //! the unknown type
27 TypeInfo TypeInfo::m_unknownType("");
30 void TypeTable::initTypeLibraries()
32 if (!typeTablesInited) {
33 TypeTable::loadTypeTables();
37 void TypeTable::loadTypeTables()
39 typeTablesInited = true;
41 const QStringList files = KGlobal::dirs()->findAllResources("types", "*.kdbgtt",
42 false, true);
44 if (files.isEmpty()) {
45 TRACE("no type tables found");
46 return;
49 for (Q3ValueListConstIterator<QString> p = files.begin(); p != files.end(); ++p) {
50 typeTables.push_back(TypeTable());
51 typeTables.back().loadFromFile(*p);
56 TypeTable::TypeTable() :
57 m_printQStringDataCmd(0)
59 m_typeDict.setAutoDelete(true);
60 // aliasDict keeps only pointers to items into typeDict
61 m_aliasDict.setAutoDelete(false);
64 TypeTable::~TypeTable()
66 delete[] m_printQStringDataCmd;
67 while (!m_templates.empty()) {
68 delete m_templates.begin()->second;
69 m_templates.erase(m_templates.begin());
74 static const char TypeTableGroup[] = "Type Table";
75 static const char LibDisplayName[] = "LibDisplayName";
76 static const char ShlibRE[] = "ShlibRE";
77 static const char EnableBuiltin[] = "EnableBuiltin";
78 static const char PrintQStringCmd[] = "PrintQStringCmd";
79 static const char TypesEntryFmt[] = "Types%d";
80 static const char DisplayEntry[] = "Display";
81 static const char AliasEntry[] = "Alias";
82 static const char TemplateEntry[] = "Template";
83 static const char ExprEntryFmt[] = "Expr%d";
84 static const char FunctionGuardEntryFmt[] = "FunctionGuard%d";
87 void TypeTable::loadFromFile(const QString& fileName)
89 TRACE("reading file " + fileName);
90 KConfig confFile(fileName, KConfig::SimpleConfig);
93 * Read library name and properties.
95 KConfigGroup cf = confFile.group(TypeTableGroup);
96 m_displayName = cf.readEntry(LibDisplayName);
97 if (m_displayName.isEmpty()) {
98 // use file name instead
99 QFileInfo fi(fileName);
100 m_displayName = fi.baseName(true);
103 m_shlibNameRE = QRegExp(cf.readEntry(ShlibRE));
104 m_enabledBuiltins = cf.readEntry(EnableBuiltin, QStringList());
106 QString printQString = cf.readEntry(PrintQStringCmd);
107 const char* ascii = printQString.ascii();
108 if (ascii == 0)
109 ascii = "";
110 m_printQStringDataCmd = new char[strlen(ascii)+1];
111 strcpy(m_printQStringDataCmd, ascii);
114 * Get the types. We search for entries of kind Types1, Types2, etc.
115 * because a single entry Types could get rather long for large
116 * libraries.
118 QString typesEntry;
119 for (int i = 1; ; i++) {
120 // next bunch of types
121 KConfigGroup cf = confFile.group(TypeTableGroup);
122 typesEntry.sprintf(TypesEntryFmt, i);
123 if (!cf.hasKey(typesEntry))
124 break;
126 QStringList typeNames = cf.readEntry(typesEntry, QStringList());
128 // now read them
129 QString alias;
130 for (QStringList::iterator it = typeNames.begin(); it != typeNames.end(); ++it)
132 KConfigGroup cf = confFile.group(*it);
133 // check if this is an alias
134 alias = cf.readEntry(AliasEntry);
135 if (alias.isEmpty()) {
136 readType(cf, *it);
137 } else {
138 // look up the alias type and insert it
139 TypeInfo* info = m_typeDict[alias];
140 if (info == 0) {
141 TRACE(*it + ": alias " + alias + " not found");
142 } else {
143 m_aliasDict.insert(alias, info);
144 TRACE(*it + ": alias " + alias);
148 } // for all Types%d
151 void TypeTable::readType(const KConfigGroup& cf, const QString& type)
153 // the display string
154 QString expr = cf.readEntry(DisplayEntry);
156 TypeInfo* info = new TypeInfo(expr);
157 if (info->m_numExprs == 0) {
158 TRACE("bogus type " + type + ": no %% in Display: " + expr);
159 delete info;
160 return;
163 info->m_templatePattern = cf.readEntry(TemplateEntry);
165 // Expr1, Expr2, etc...
166 QString exprEntry;
167 QString funcGuardEntry;
168 for (int j = 0; j < info->m_numExprs; j++) {
169 exprEntry.sprintf(ExprEntryFmt, j+1);
170 expr = cf.readEntry(exprEntry);
171 info->m_exprStrings[j] = expr;
173 funcGuardEntry.sprintf(FunctionGuardEntryFmt, j+1);
174 expr = cf.readEntry(funcGuardEntry);
175 info->m_guardStrings[j] = expr;
178 // add the new type
179 if (info->m_templatePattern.find('<') < 0)
180 m_typeDict.insert(type, info);
181 else
182 m_templates[type] = info;
183 TRACE(type + QString().sprintf(": %d exprs", info->m_numExprs));
186 void TypeTable::copyTypes(Q3Dict<TypeInfo>& dict)
188 for (Q3DictIterator<TypeInfo> it = m_typeDict; it != 0; ++it) {
189 dict.insert(it.currentKey(), it);
191 for (Q3DictIterator<TypeInfo> it = m_aliasDict; it != 0; ++it) {
192 dict.insert(it.currentKey(), it);
196 bool TypeTable::isEnabledBuiltin(const QString& feature) const
198 return m_enabledBuiltins.find(feature) != m_enabledBuiltins.end();
201 TypeInfo::TypeInfo(const QString& displayString)
203 // decompose the input into the parts
204 int i = 0;
205 int startIdx = 0;
206 int idx;
207 while (i < typeInfoMaxExpr &&
208 (idx = displayString.find('%', startIdx)) >= 0)
210 m_displayString[i] = displayString.mid(startIdx, idx-startIdx);
211 startIdx = idx+1;
212 i++;
214 m_numExprs = i;
216 * Remaining string; note that there's one more display string than
217 * sub-expressions.
219 m_displayString[i] = displayString.right(displayString.length()-startIdx);
222 TypeInfo::~TypeInfo()
227 ProgramTypeTable::ProgramTypeTable() :
228 m_parseQt2QStrings(false),
229 m_QCharIsShort(false),
230 m_printQStringDataCmd(0)
232 m_types.setAutoDelete(false); /* paranoia */
233 m_aliasDict.setAutoDelete(false); /* paranoia */
236 ProgramTypeTable::~ProgramTypeTable()
240 void ProgramTypeTable::loadTypeTable(TypeTable* table)
242 table->copyTypes(m_types);
244 // add templates
245 const TypeTable::TypeMap& t = table->templates();
246 std::transform(t.begin(), t.end(),
247 std::inserter(m_templates, m_templates.begin()),
248 std::ptr_fun(template2Info));
250 // check whether to enable builtin QString support
251 if (!m_parseQt2QStrings) {
252 m_parseQt2QStrings = table->isEnabledBuiltin("QString::Data");
254 if (!m_QCharIsShort) {
255 m_QCharIsShort = table->isEnabledBuiltin("QCharIsShort");
257 if (!m_printQStringDataCmd && *table->printQStringDataCmd()) {
258 m_printQStringDataCmd = table->printQStringDataCmd();
262 ProgramTypeTable::TemplateMap::value_type
263 ProgramTypeTable::template2Info(const TypeTable::TypeMap::value_type& tt)
265 QStringList args = splitTemplateArgs(tt.second->m_templatePattern);
267 TemplateMap::value_type result(args.front(), TemplateInfo());
268 result.second.type = tt.second;
269 args.pop_front();
270 result.second.templateArgs = args;
271 return result;
275 * Splits the name \a t into the template name and its arguments.
276 * The first entry of the returned list is the template name, the remaining
277 * entries are the arguments.
279 QStringList ProgramTypeTable::splitTemplateArgs(const QString& t)
281 QStringList result;
282 result.push_back(t);
284 int i = t.find('<');
285 if (i < 0)
286 return result;
288 // split off the template name
289 result.front().truncate(i);
291 i++; // skip '<'
292 // look for the next comma or the closing '>', skipping nested '<>'
293 int nest = 0;
294 int start = i;
295 for (; unsigned(i) < t.length() && nest >= 0; i++)
297 if (t[i] == '<')
298 nest++;
299 else if (t[i] == '>')
300 nest--;
301 else if (nest == 0 && t[i] == ',') {
302 // found end of argument
303 QString arg = t.mid(start, i-start);
304 result.push_back(arg);
305 start = i+1; // skip ','
308 // accept the template only if the closing '>' is the last character
309 if (nest < 0 && unsigned(i) == t.length()) {
310 QString arg = t.mid(start, i-start-1);
311 result.push_back(arg);
312 } else {
313 result.clear();
314 result.push_back(t);
316 return result;
319 TypeInfo* ProgramTypeTable::lookup(QString type)
322 * Registered aliases contain the complete template parameter list.
323 * Check for an alias first so that this case is out of the way.
325 if (TypeInfo* result = m_aliasDict[type])
326 return result;
329 * Check for a normal type. Even if type is a template instance,
330 * it could have been registered as a normal type instead of a pattern.
332 if (TypeInfo* result = m_types[type])
333 return result;
336 * The hard part: Look up a template.
338 QStringList parts = splitTemplateArgs(type);
339 if (parts.size() == 1)
340 return 0; // not a template
342 // We can have several patterns for the same template name.
343 std::pair<TemplateMap::const_iterator, TemplateMap::const_iterator> range =
344 m_templates.equal_range(parts.front());
345 // We pick the one that has the wildcards in the later parameters.
346 unsigned minPenalty = ~0U;
347 TypeInfo* result = 0;
348 parts.pop_front();
350 for (TemplateMap::const_iterator i = range.first; i != range.second; ++i)
352 const QStringList& pat = i->second.templateArgs;
353 if (parts.size() < pat.size())
354 continue; // too few arguments
356 // a "*" in the last position of the pattern matches all arguments
357 // at the end of the template's arguments
358 if (parts.size() > pat.size() && pat.back() != "*")
359 continue; // too many arguments and no wildcard
361 QStringList::const_iterator t = parts.begin();
362 QStringList::const_iterator p = pat.begin();
363 unsigned accumPenalty = 0;
364 bool equal = true;
365 unsigned penalty = ~(~0U>>1); // 1 in the leading bit
366 while (equal && p != pat.end())
368 if (*p == "*")
369 accumPenalty |= penalty; // penalize wildcards
370 else
371 equal = *p == *t;
372 ++p, ++t, penalty >>= 1;
374 if (equal)
376 if (accumPenalty == 0)
377 return i->second.type;
378 if (accumPenalty < minPenalty) {
379 result = i->second.type;
380 minPenalty = accumPenalty;
384 return result;
387 void ProgramTypeTable::registerAlias(const QString& name, TypeInfo* type)
389 ASSERT(lookup(name) == 0 || lookup(name) == type);
390 m_aliasDict.insert(name, type);
393 void ProgramTypeTable::loadLibTypes(const QStringList& libs)
395 for (QStringList::const_iterator it = libs.begin(); it != libs.end(); ++it)
397 // look up the library
398 for (std::list<TypeTable>::iterator t = typeTables.begin(); t != typeTables.end(); ++t)
400 if (t->matchFileName(*it))
402 TRACE("adding types for " + *it);
403 loadTypeTable(&*t);