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.
10 #include <kstandarddirs.h>
11 #include <ksimpleconfig.h>
17 #include "typetable.h"
20 //! the TypeTables of all known libraries
21 static QList
<TypeTable
> typeTables
;
22 bool typeTablesInited
= false;
25 //! an indentifier for wchar_t
26 TypeInfo
TypeInfo::m_wchartType("");
28 TypeInfo
TypeInfo::m_unknownType("");
31 void TypeTable::initTypeLibraries()
33 if (!typeTablesInited
) {
34 TypeTable::loadTypeTables();
38 void TypeTable::loadTypeTables()
40 typeTablesInited
= true;
42 const QStringList files
= KGlobal::dirs()->findAllResources("types", "*.kdbgtt",
45 if (files
.isEmpty()) {
46 TRACE("no type tables found");
51 for (QValueListConstIterator
<QString
> p
= files
.begin(); p
!= files
.end(); ++p
) {
53 TypeTable
* newTable
= new TypeTable
;
54 newTable
->loadFromFile(fileName
);
55 typeTables
.append(newTable
);
60 TypeTable::TypeTable() :
61 m_printQStringDataCmd(0)
63 m_typeDict
.setAutoDelete(true);
64 // aliasDict keeps only pointers to items into typeDict
65 m_aliasDict
.setAutoDelete(false);
68 TypeTable::~TypeTable()
70 delete[] m_printQStringDataCmd
;
71 while (!m_templates
.empty()) {
72 delete m_templates
.begin()->second
;
73 m_templates
.erase(m_templates
.begin());
78 static const char TypeTableGroup
[] = "Type Table";
79 static const char LibDisplayName
[] = "LibDisplayName";
80 static const char ShlibRE
[] = "ShlibRE";
81 static const char EnableBuiltin
[] = "EnableBuiltin";
82 static const char PrintQStringCmd
[] = "PrintQStringCmd";
83 static const char TypesEntryFmt
[] = "Types%d";
84 static const char DisplayEntry
[] = "Display";
85 static const char AliasEntry
[] = "Alias";
86 static const char TemplateEntry
[] = "Template";
87 static const char ExprEntryFmt
[] = "Expr%d";
88 static const char FunctionGuardEntryFmt
[] = "FunctionGuard%d";
91 void TypeTable::loadFromFile(const QString
& fileName
)
93 TRACE("reading file " + fileName
);
94 KSimpleConfig
cf(fileName
, true); /* read-only */
97 * Read library name and properties.
99 cf
.setGroup(TypeTableGroup
);
100 m_displayName
= cf
.readEntry(LibDisplayName
);
101 if (m_displayName
.isEmpty()) {
102 // use file name instead
103 QFileInfo
fi(fileName
);
104 m_displayName
= fi
.baseName(true);
107 m_shlibNameRE
= QRegExp(cf
.readEntry(ShlibRE
));
108 m_enabledBuiltins
= cf
.readListEntry(EnableBuiltin
);
110 QString printQString
= cf
.readEntry(PrintQStringCmd
);
111 const char* ascii
= printQString
.ascii();
114 m_printQStringDataCmd
= new char[strlen(ascii
)+1];
115 strcpy(m_printQStringDataCmd
, ascii
);
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
123 for (int i
= 1; ; i
++) {
124 // next bunch of types
125 cf
.setGroup(TypeTableGroup
);
126 typesEntry
.sprintf(TypesEntryFmt
, i
);
127 if (!cf
.hasKey(typesEntry
))
130 QStringList typeNames
= cf
.readListEntry(typesEntry
, ',');
134 for (QStringList::iterator it
= typeNames
.begin(); it
!= typeNames
.end(); ++it
)
137 // check if this is an alias
138 alias
= cf
.readEntry(AliasEntry
);
139 if (alias
.isEmpty()) {
142 // look up the alias type and insert it
143 TypeInfo
* info
= m_typeDict
[alias
];
145 TRACE(*it
+ ": alias " + alias
+ " not found");
147 m_aliasDict
.insert(alias
, info
);
148 TRACE(*it
+ ": alias " + alias
);
155 void TypeTable::readType(KConfigBase
& cf
, const QString
& type
)
157 // the display string
158 QString expr
= cf
.readEntry(DisplayEntry
);
160 TypeInfo
* info
= new TypeInfo(expr
);
161 if (info
->m_numExprs
== 0) {
162 TRACE("bogus type " + type
+ ": no %% in Display: " + expr
);
167 info
->m_templatePattern
= cf
.readEntry(TemplateEntry
);
169 // Expr1, Expr2, etc...
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
;
183 if (info
->m_templatePattern
.find('<') < 0)
184 m_typeDict
.insert(type
, info
);
186 m_templates
[type
] = info
;
187 TRACE(type
+ QString().sprintf(": %d exprs", info
->m_numExprs
));
190 void TypeTable::copyTypes(QDict
<TypeInfo
>& dict
)
192 for (QDictIterator
<TypeInfo
> it
= m_typeDict
; it
!= 0; ++it
) {
193 dict
.insert(it
.currentKey(), it
);
195 for (QDictIterator
<TypeInfo
> it
= m_aliasDict
; it
!= 0; ++it
) {
196 dict
.insert(it
.currentKey(), it
);
200 bool TypeTable::isEnabledBuiltin(const QString
& feature
) const
202 return m_enabledBuiltins
.find(feature
) != m_enabledBuiltins
.end();
205 TypeInfo::TypeInfo(const QString
& displayString
)
207 // decompose the input into the parts
211 while (i
< typeInfoMaxExpr
&&
212 (idx
= displayString
.find('%', startIdx
)) >= 0)
214 m_displayString
[i
] = displayString
.mid(startIdx
, idx
-startIdx
);
220 * Remaining string; note that there's one more display string than
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::loadTypeTable(TypeTable
* table
)
246 table
->copyTypes(m_types
);
249 const TypeTable::TypeMap
& t
= table
->templates();
250 std::transform(t
.begin(), t
.end(),
251 std::inserter(m_templates
, m_templates
.begin()),
252 std::ptr_fun(template2Info
));
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 ProgramTypeTable::TemplateMap::value_type
267 ProgramTypeTable::template2Info(const TypeTable::TypeMap::value_type
& tt
)
269 QStringList args
= splitTemplateArgs(tt
.second
->m_templatePattern
);
271 TemplateMap::value_type
result(args
.front(), TemplateInfo());
272 result
.second
.type
= tt
.second
;
274 result
.second
.templateArgs
= args
;
279 * Splits the name \a t into the template name and its arguments.
280 * The first entry of the returned list is the template name, the remaining
281 * entries are the arguments.
283 QStringList
ProgramTypeTable::splitTemplateArgs(const QString
& t
)
292 // split off the template name
293 result
.front().truncate(i
);
296 // look for the next comma or the closing '>', skipping nested '<>'
299 for (; unsigned(i
) < t
.length() && nest
>= 0; i
++)
303 else if (t
[i
] == '>')
305 else if (nest
== 0 && t
[i
] == ',') {
306 // found end of argument
307 QString arg
= t
.mid(start
, i
-start
);
308 result
.push_back(arg
);
309 start
= i
+1; // skip ','
312 // accept the template only if the closing '>' is the last character
313 if (nest
< 0 && unsigned(i
) == t
.length()) {
314 QString arg
= t
.mid(start
, i
-start
-1);
315 result
.push_back(arg
);
323 TypeInfo
* ProgramTypeTable::lookup(QString type
)
326 * Registered aliases contain the complete template parameter list.
327 * Check for an alias first so that this case is out of the way.
329 if (TypeInfo
* result
= m_aliasDict
[type
])
333 * Check for a normal type. Even if type is a template instance,
334 * it could have been registered as a normal type instead of a pattern.
336 if (TypeInfo
* result
= m_types
[type
])
340 * The hard part: Look up a template.
342 QStringList parts
= splitTemplateArgs(type
);
343 if (parts
.size() == 1)
344 return 0; // not a template
346 // We can have several patterns for the same template name.
347 std::pair
<TemplateMap::const_iterator
, TemplateMap::const_iterator
> range
=
348 m_templates
.equal_range(parts
.front());
349 // We pick the one that has the wildcards in the later parameters.
350 unsigned minPenalty
= ~0U;
351 TypeInfo
* result
= 0;
354 for (TemplateMap::const_iterator i
= range
.first
; i
!= range
.second
; ++i
)
356 const QStringList
& pat
= i
->second
.templateArgs
;
357 if (parts
.size() < pat
.size())
358 continue; // too few arguments
360 // a "*" in the last position of the pattern matches all arguments
361 // at the end of the template's arguments
362 if (parts
.size() > pat
.size() && pat
.back() != "*")
363 continue; // too many arguments and no wildcard
365 QStringList::const_iterator t
= parts
.begin();
366 QStringList::const_iterator p
= pat
.begin();
367 unsigned penalty
= 0;
369 for (int j
= 0; equal
&& p
!= pat
.end(); ++p
, ++t
, ++j
)
372 penalty
+= 1U << j
; // penalize wildcards
379 return i
->second
.type
;
380 if (penalty
< minPenalty
)
381 result
= i
->second
.type
;
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 QStrList
& libs
)
395 QStrListIterator it
= libs
;
398 * We use a copy of the list of known libraries, from which we delete
399 * those libs that we already have added. This way we avoid to load a
402 QList
<TypeTable
> allTables
= typeTables
; /* shallow copy! */
403 allTables
.setAutoDelete(false); /* important! */
405 for (; it
&& allTables
.count() > 0; ++it
)
407 // look up the library
409 for (TypeTable
* t
= allTables
.first(); t
!= 0; t
= allTables
.next())
411 if (t
->matchFileName(it
))
413 TRACE("adding types for " + QString(it
));
418 * continue the search (due to remove's unpredictable
419 * behavior of setting the current item we simply go
420 * through the whole list again)