Ensure that user-defined type tables override system-provided ones.
[kdbg.git] / kdbg / typetable.cpp
blobd1cc49e183acd3a98d602a3452ee744d5c313534
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 <kstddirs.h>
11 #include <ksimpleconfig.h>
12 #ifdef HAVE_CONFIG_H
13 #include "config.h"
14 #endif
15 #include "typetable.h"
16 #include "mydebug.h"
18 //! the TypeTables of all known libraries
19 static QList<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 false, true);
43 if (files.isEmpty()) {
44 TRACE("no type tables found");
45 return;
48 QString fileName;
49 for (QValueListConstIterator<QString> p = files.begin(); p != files.end(); ++p) {
50 fileName = *p;
51 TypeTable* newTable = new TypeTable;
52 newTable->loadFromFile(fileName);
53 typeTables.append(newTable);
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;
72 static const char TypeTableGroup[] = "Type Table";
73 static const char LibDisplayName[] = "LibDisplayName";
74 static const char ShlibRE[] = "ShlibRE";
75 static const char EnableBuiltin[] = "EnableBuiltin";
76 static const char PrintQStringCmd[] = "PrintQStringCmd";
77 static const char TypesEntryFmt[] = "Types%d";
78 static const char DisplayEntry[] = "Display";
79 static const char AliasEntry[] = "Alias";
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 KSimpleConfig cf(fileName, true); /* read-only */
90 * Read library name and properties.
92 cf.setGroup(TypeTableGroup);
93 m_displayName = cf.readEntry(LibDisplayName);
94 if (m_displayName.isEmpty()) {
95 // use file name instead
96 int slash = fileName.findRev('\\');
97 m_displayName =
98 slash >= 0 ? fileName.mid(slash+1, fileName.length()) : fileName;
99 int dot = m_displayName.findRev('.');
100 if (dot > 0) {
101 m_displayName.truncate(dot);
105 m_shlibNameRE = QRegExp(cf.readEntry(ShlibRE));
106 cf.readListEntry(EnableBuiltin, m_enabledBuiltins);
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 QStrList typeNames;
121 QString typesEntry;
122 for (int i = 1; ; i++) {
123 // next bunch of types
124 cf.setGroup(TypeTableGroup);
125 typesEntry.sprintf(TypesEntryFmt, i);
126 if (!cf.hasKey(typesEntry))
127 break;
128 cf.readListEntry(typesEntry, typeNames, ',');
130 // now read them
131 QString alias;
132 for (QListIterator<char> it(typeNames); it != 0; ++it) {
133 cf.setGroup(it.current());
134 // check if this is an alias
135 alias = cf.readEntry(AliasEntry);
136 if (alias.isEmpty()) {
137 readType(cf, it);
138 } else {
139 // look up the alias type and insert it
140 TypeInfo* info = m_typeDict[alias];
141 if (info == 0) {
142 TRACE(QString().sprintf("<%s>: alias %s not found",
143 it.operator char*(), alias.data()));
144 } else {
145 m_aliasDict.insert(alias, info);
146 TRACE(QString().sprintf("<%s>: alias <%s>",
147 it.operator char*(), alias.data()));
151 } // for all Types%d
154 void TypeTable::readType(KConfigBase& cf, const char* type)
156 // the display string
157 QString expr = cf.readEntry(DisplayEntry);
159 TypeInfo* info = new TypeInfo(expr);
160 if (info->m_numExprs == 0) {
161 TRACE(QString().sprintf("bogus type %s: no %% in Display: '%s'",
162 type, expr.data()));
163 delete info;
164 return;
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 m_typeDict.insert(type, info);
182 TRACE(QString().sprintf("<%s>: %d exprs", type,
183 info->m_numExprs));
186 void TypeTable::copyTypes(QDict<TypeInfo>& dict)
188 for (QDictIterator<TypeInfo> it = m_typeDict; it != 0; ++it) {
189 dict.insert(it.currentKey(), it);
191 for (QDictIterator<TypeInfo> it = m_aliasDict; it != 0; ++it) {
192 dict.insert(it.currentKey(), it);
196 bool TypeTable::isEnabledBuiltin(const char* feature)
198 char* f = m_enabledBuiltins.first();
199 while (f) {
200 if (strcmp(feature, f) == 0)
201 return true;
202 f = m_enabledBuiltins.next();
204 return false;
207 TypeInfo::TypeInfo(const QString& displayString)
209 // decompose the input into the parts
210 int i = 0;
211 int startIdx = 0;
212 int idx;
213 while (i < typeInfoMaxExpr &&
214 (idx = displayString.find('%', startIdx)) >= 0)
216 m_displayString[i] = displayString.mid(startIdx, idx-startIdx);
217 startIdx = idx+1;
218 i++;
220 m_numExprs = i;
222 * Remaining string; note that there's one more display string than
223 * sub-expressions.
225 m_displayString[i] = displayString.right(displayString.length()-startIdx);
228 TypeInfo::~TypeInfo()
233 ProgramTypeTable::ProgramTypeTable() :
234 m_parseQt2QStrings(false),
235 m_QCharIsShort(false),
236 m_printQStringDataCmd(0)
238 m_types.setAutoDelete(false); /* paranoia */
239 m_aliasDict.setAutoDelete(false); /* paranoia */
242 ProgramTypeTable::~ProgramTypeTable()
246 void ProgramTypeTable::clear()
248 m_types.clear();
251 void ProgramTypeTable::loadTypeTable(TypeTable* table)
253 table->copyTypes(m_types);
254 // check whether to enable builtin QString support
255 if (!m_parseQt2QStrings) {
256 m_parseQt2QStrings = table->isEnabledBuiltin("QString::Data");
258 if (!m_QCharIsShort) {
259 m_QCharIsShort = table->isEnabledBuiltin("QCharIsShort");
261 if (!m_printQStringDataCmd && *table->printQStringDataCmd()) {
262 m_printQStringDataCmd = table->printQStringDataCmd();
266 TypeInfo* ProgramTypeTable::lookup(const char* type)
268 TypeInfo* result = m_types[type];
269 if (result == 0) {
270 result = m_aliasDict[type];
272 return result;
275 void ProgramTypeTable::registerAlias(const QString& name, TypeInfo* type)
277 ASSERT(lookup(name) == 0 || lookup(name) == type);
278 m_aliasDict.insert(name, type);
281 void ProgramTypeTable::loadLibTypes(const QStrList& libs)
283 QStrListIterator it = libs;
286 * We use a copy of the list of known libraries, from which we delete
287 * those libs that we already have added. This way we avoid to load a
288 * library twice.
290 QList<TypeTable> allTables = typeTables; /* shallow copy! */
291 allTables.setAutoDelete(false); /* important! */
293 for (; it && allTables.count() > 0; ++it)
295 // look up the library
296 repeatLookup:;
297 for (TypeTable* t = allTables.first(); t != 0; t = allTables.next())
299 if (t->matchFileName(it))
301 TRACE("adding types for " + QString(it));
302 loadTypeTable(t);
303 // remove the table
304 allTables.remove();
306 * continue the search (due to remove's unpredictable
307 * behavior of setting the current item we simply go
308 * through the whole list again)
310 goto repeatLookup;