Added a context menu to the local variables window to move
[kdbg.git] / kdbg / typetable.cpp
blobb11620ab06ac242718557eeaa70643dcabbd48d1
1 // $Id$
3 // Copyright by Johannes Sixt
4 // This file is under GPL, the GNU General Public Licence
6 #include <qdir.h>
7 #include <qlist.h>
8 #if QT_VERSION < 200
9 #include <kapp.h>
10 #else
11 #include <kglobal.h>
12 #include <kstddirs.h>
13 #endif
14 #include <ksimpleconfig.h>
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 // the unknown type
24 TypeInfo TypeInfo::m_unknownType("");
27 void TypeTable::initTypeLibraries()
29 if (!typeTablesInited) {
30 TypeTable::loadTypeTables();
34 void TypeTable::loadTypeTables()
36 typeTablesInited = true;
38 #if QT_VERSION < 200
39 QDir dir(KApplication::kde_datadir() + "/kdbg/types");
40 const QStrList* files = dir.entryList("*.kdbgtt");
42 if (files == 0) {
43 TRACE("no type tables found");
44 return;
46 #else
47 const QStringList files = KGlobal::dirs()->findAllResources("types", "*.kdbgtt");
49 if (files.isEmpty()) {
50 TRACE("no type tables found");
51 return;
53 #endif
55 QString fileName;
56 #if QT_VERSION < 200
57 for (QListIterator<char> it(*files); it != 0; ++it) {
58 fileName = dir.filePath(it.current());
59 #else
60 for (QValueListConstIterator<QString> p = files.begin(); p != files.end(); ++p) {
61 fileName = *p;
62 #endif
63 TypeTable* newTable = new TypeTable;
64 newTable->loadFromFile(fileName);
65 typeTables.append(newTable);
70 TypeTable::TypeTable()
72 m_typeDict.setAutoDelete(true);
73 // aliasDict keeps only pointers to items into typeDict
74 m_aliasDict.setAutoDelete(false);
77 TypeTable::~TypeTable()
82 static const char TypeTableGroup[] = "Type Table";
83 static const char LibDisplayName[] = "LibDisplayName";
84 static const char ShlibRE[] = "ShlibRE";
85 static const char EnableBuiltin[] = "EnableBuiltin";
86 static const char TypesEntryFmt[] = "Types%d";
87 static const char DisplayEntry[] = "Display";
88 static const char AliasEntry[] = "Alias";
89 static const char ExprEntryFmt[] = "Expr%d";
90 static const char FunctionGuardEntryFmt[] = "FunctionGuard%d";
93 void TypeTable::loadFromFile(const QString& fileName)
95 TRACE("reading file " + fileName);
96 KSimpleConfig cf(fileName, true); /* read-only */
99 * Read library name and properties.
101 cf.setGroup(TypeTableGroup);
102 m_displayName = cf.readEntry(LibDisplayName);
103 if (m_displayName.isEmpty()) {
104 // use file name instead
105 int slash = fileName.findRev('\\');
106 m_displayName =
107 slash >= 0 ? fileName.mid(slash+1, fileName.length()) : fileName;
108 int dot = m_displayName.findRev('.');
109 if (dot > 0) {
110 m_displayName.truncate(dot);
114 m_shlibNameRE = QRegExp(cf.readEntry(ShlibRE));
115 cf.readListEntry(EnableBuiltin, m_enabledBuiltins);
118 * Get the types. We search for entries of kind Types1, Types2, etc.
119 * because a single entry Types could get rather long for large
120 * libraries.
122 QStrList typeNames;
123 QString typesEntry;
124 for (int i = 1; ; i++) {
125 // next bunch of types
126 cf.setGroup(TypeTableGroup);
127 typesEntry.sprintf(TypesEntryFmt, i);
128 if (!cf.hasKey(typesEntry))
129 break;
130 cf.readListEntry(typesEntry, typeNames, ',');
132 // now read them
133 QString alias;
134 for (QListIterator<char> it(typeNames); it != 0; ++it) {
135 cf.setGroup(it.current());
136 // check if this is an alias
137 alias = cf.readEntry(AliasEntry);
138 if (alias.isEmpty()) {
139 readType(cf, it);
140 } else {
141 // look up the alias type and insert it
142 TypeInfo* info = m_typeDict[alias];
143 if (info == 0) {
144 TRACE(QString().sprintf("<%s>: alias %s not found",
145 it.operator char*(), alias.data()));
146 } else {
147 m_aliasDict.insert(alias, info);
148 TRACE(QString().sprintf("<%s>: alias <%s>",
149 it.operator char*(), alias.data()));
153 } // for all Types%d
156 void TypeTable::readType(KConfigBase& cf, const char* type)
158 // the display string
159 QString expr = cf.readEntry(DisplayEntry);
161 TypeInfo* info = new TypeInfo(expr);
162 if (info->m_numExprs == 0) {
163 TRACE(QString().sprintf("bogus type %s: no %% in Display: '%s'",
164 type, expr.data()));
165 delete info;
166 return;
169 // Expr1, Expr2, etc...
170 QString exprEntry;
171 QString funcGuardEntry;
172 for (int j = 0; j < info->m_numExprs; j++) {
173 exprEntry.sprintf(ExprEntryFmt, j+1);
174 expr = cf.readEntry(exprEntry);
175 info->m_exprStrings[j] = expr;
177 funcGuardEntry.sprintf(FunctionGuardEntryFmt, j+1);
178 expr = cf.readEntry(funcGuardEntry);
179 info->m_guardStrings[j] = expr;
182 // add the new type
183 m_typeDict.insert(type, info);
184 TRACE(QString().sprintf("<%s>: %d exprs", type,
185 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 char* feature)
200 char* f = m_enabledBuiltins.first();
201 while (f) {
202 if (strcmp(feature, f) == 0)
203 return true;
204 f = m_enabledBuiltins.next();
206 return false;
209 TypeInfo::TypeInfo(const QString& displayString)
211 // decompose the input into the parts
212 int i = 0;
213 int startIdx = 0;
214 int idx;
215 while (i < typeInfoMaxExpr &&
216 (idx = displayString.find('%', startIdx)) >= 0)
218 m_displayString[i] = displayString.mid(startIdx, idx-startIdx);
219 startIdx = idx+1;
220 i++;
222 m_numExprs = i;
224 * Remaining string; note that there's one more display string than
225 * sub-expressions.
227 m_displayString[i] = displayString.right(displayString.length()-startIdx);
230 TypeInfo::~TypeInfo()
235 ProgramTypeTable::ProgramTypeTable() :
236 m_parseQt2QStrings(false)
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");
260 TypeInfo* ProgramTypeTable::lookup(const char* type)
262 TypeInfo* result = m_types[type];
263 if (result == 0) {
264 result = m_aliasDict[type];
266 return result;
269 void ProgramTypeTable::registerAlias(const QString& name, TypeInfo* type)
271 ASSERT(lookup(name) == 0 || lookup(name) == type);
272 m_aliasDict.insert(name, type);
275 #if QT_VERSION < 200
276 typedef QListIterator<char> QStrListIterator;
277 #endif
279 void ProgramTypeTable::loadLibTypes(const QStrList& libs)
281 QStrListIterator it = libs;
284 * We use a copy of the list of known libraries, from which we delete
285 * those libs that we already have added. This way we avoid to load a
286 * library twice.
288 QList<TypeTable> allTables = typeTables; /* shallow copy! */
289 allTables.setAutoDelete(false); /* important! */
291 for (; it && allTables.count() > 0; ++it)
293 // look up the library
294 repeatLookup:;
295 for (TypeTable* t = allTables.first(); t != 0; t = allTables.next())
297 if (t->matchFileName(it))
299 TRACE("adding types for " + QString(it));
300 loadTypeTable(t);
301 // remove the table
302 allTables.remove();
304 * continue the search (due to remove's unpredictable
305 * behavior of setting the current item we simply go
306 * through the whole list again)
308 goto repeatLookup;