Remember the width of column 1 of Locals and Watch window across sessions.
[kdbg.git] / kdbg / typetable.cpp
blob945bf89721e93ae900786aacb8506a6bf9ab70d9
1 // $Id$
3 // Copyright by Johannes Sixt
4 // This file is under GPL, the GNU General Public Licence
6 #include <qdir.h>
7 #include <qptrlist.h>
8 #include <kglobal.h>
9 #include <kstddirs.h>
10 #include <ksimpleconfig.h>
11 #ifdef HAVE_CONFIG_H
12 #include "config.h"
13 #endif
14 #include "typetable.h"
15 #include "mydebug.h"
17 // the TypeTables of all known libraries
18 static QList<TypeTable> typeTables;
19 bool typeTablesInited = false;
22 // an indentifier for wchar_t
23 TypeInfo TypeInfo::m_wchartType("");
24 // the unknown type
25 TypeInfo TypeInfo::m_unknownType("");
28 void TypeTable::initTypeLibraries()
30 if (!typeTablesInited) {
31 TypeTable::loadTypeTables();
35 void TypeTable::loadTypeTables()
37 typeTablesInited = true;
39 const QStringList files = KGlobal::dirs()->findAllResources("types", "*.kdbgtt");
41 if (files.isEmpty()) {
42 TRACE("no type tables found");
43 return;
46 QString fileName;
47 for (QValueListConstIterator<QString> p = files.begin(); p != files.end(); ++p) {
48 fileName = *p;
49 TypeTable* newTable = new TypeTable;
50 newTable->loadFromFile(fileName);
51 typeTables.append(newTable);
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;
70 static const char TypeTableGroup[] = "Type Table";
71 static const char LibDisplayName[] = "LibDisplayName";
72 static const char ShlibRE[] = "ShlibRE";
73 static const char EnableBuiltin[] = "EnableBuiltin";
74 static const char PrintQStringCmd[] = "PrintQStringCmd";
75 static const char TypesEntryFmt[] = "Types%d";
76 static const char DisplayEntry[] = "Display";
77 static const char AliasEntry[] = "Alias";
78 static const char ExprEntryFmt[] = "Expr%d";
79 static const char FunctionGuardEntryFmt[] = "FunctionGuard%d";
82 void TypeTable::loadFromFile(const QString& fileName)
84 TRACE("reading file " + fileName);
85 KSimpleConfig cf(fileName, true); /* read-only */
88 * Read library name and properties.
90 cf.setGroup(TypeTableGroup);
91 m_displayName = cf.readEntry(LibDisplayName);
92 if (m_displayName.isEmpty()) {
93 // use file name instead
94 int slash = fileName.findRev('\\');
95 m_displayName =
96 slash >= 0 ? fileName.mid(slash+1, fileName.length()) : fileName;
97 int dot = m_displayName.findRev('.');
98 if (dot > 0) {
99 m_displayName.truncate(dot);
103 m_shlibNameRE = QRegExp(cf.readEntry(ShlibRE));
104 cf.readListEntry(EnableBuiltin, m_enabledBuiltins);
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 QStrList typeNames;
119 QString typesEntry;
120 for (int i = 1; ; i++) {
121 // next bunch of types
122 cf.setGroup(TypeTableGroup);
123 typesEntry.sprintf(TypesEntryFmt, i);
124 if (!cf.hasKey(typesEntry))
125 break;
126 cf.readListEntry(typesEntry, typeNames, ',');
128 // now read them
129 QString alias;
130 for (QListIterator<char> it(typeNames); it != 0; ++it) {
131 cf.setGroup(it.current());
132 // check if this is an alias
133 alias = cf.readEntry(AliasEntry);
134 if (alias.isEmpty()) {
135 readType(cf, it);
136 } else {
137 // look up the alias type and insert it
138 TypeInfo* info = m_typeDict[alias];
139 if (info == 0) {
140 TRACE(QString().sprintf("<%s>: alias %s not found",
141 it.operator char*(), alias.data()));
142 } else {
143 m_aliasDict.insert(alias, info);
144 TRACE(QString().sprintf("<%s>: alias <%s>",
145 it.operator char*(), alias.data()));
149 } // for all Types%d
152 void TypeTable::readType(KConfigBase& cf, const char* type)
154 // the display string
155 QString expr = cf.readEntry(DisplayEntry);
157 TypeInfo* info = new TypeInfo(expr);
158 if (info->m_numExprs == 0) {
159 TRACE(QString().sprintf("bogus type %s: no %% in Display: '%s'",
160 type, expr.data()));
161 delete info;
162 return;
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 m_typeDict.insert(type, info);
180 TRACE(QString().sprintf("<%s>: %d exprs", type,
181 info->m_numExprs));
184 void TypeTable::copyTypes(QDict<TypeInfo>& dict)
186 for (QDictIterator<TypeInfo> it = m_typeDict; it != 0; ++it) {
187 dict.insert(it.currentKey(), it);
189 for (QDictIterator<TypeInfo> it = m_aliasDict; it != 0; ++it) {
190 dict.insert(it.currentKey(), it);
194 bool TypeTable::isEnabledBuiltin(const char* feature)
196 char* f = m_enabledBuiltins.first();
197 while (f) {
198 if (strcmp(feature, f) == 0)
199 return true;
200 f = m_enabledBuiltins.next();
202 return false;
205 TypeInfo::TypeInfo(const QString& displayString)
207 // decompose the input into the parts
208 int i = 0;
209 int startIdx = 0;
210 int idx;
211 while (i < typeInfoMaxExpr &&
212 (idx = displayString.find('%', startIdx)) >= 0)
214 m_displayString[i] = displayString.mid(startIdx, idx-startIdx);
215 startIdx = idx+1;
216 i++;
218 m_numExprs = i;
220 * Remaining string; note that there's one more display string than
221 * sub-expressions.
223 m_displayString[i] = displayString.right(displayString.length()-startIdx);
226 TypeInfo::~TypeInfo()
231 ProgramTypeTable::ProgramTypeTable() :
232 m_parseQt2QStrings(false),
233 m_QCharIsShort(false),
234 m_printQStringDataCmd(0)
236 m_types.setAutoDelete(false); /* paranoia */
237 m_aliasDict.setAutoDelete(false); /* paranoia */
240 ProgramTypeTable::~ProgramTypeTable()
244 void ProgramTypeTable::clear()
246 m_types.clear();
249 void ProgramTypeTable::loadTypeTable(TypeTable* table)
251 table->copyTypes(m_types);
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 TypeInfo* ProgramTypeTable::lookup(const char* type)
266 TypeInfo* result = m_types[type];
267 if (result == 0) {
268 result = m_aliasDict[type];
270 return result;
273 void ProgramTypeTable::registerAlias(const QString& name, TypeInfo* type)
275 ASSERT(lookup(name) == 0 || lookup(name) == type);
276 m_aliasDict.insert(name, type);
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;