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>
12 #include <kconfiggroup.h>
16 #include "typetable.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("");
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",
44 if (files
.isEmpty()) {
45 TRACE("no type tables found");
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();
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
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
))
126 QStringList typeNames
= cf
.readEntry(typesEntry
, QStringList());
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()) {
138 // look up the alias type and insert it
139 TypeInfo
* info
= m_typeDict
[alias
];
141 TRACE(*it
+ ": alias " + alias
+ " not found");
143 m_aliasDict
.insert(alias
, info
);
144 TRACE(*it
+ ": alias " + alias
);
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
);
163 info
->m_templatePattern
= cf
.readEntry(TemplateEntry
);
165 // Expr1, Expr2, etc...
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
;
179 if (info
->m_templatePattern
.find('<') < 0)
180 m_typeDict
.insert(type
, info
);
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
207 while (i
< typeInfoMaxExpr
&&
208 (idx
= displayString
.find('%', startIdx
)) >= 0)
210 m_displayString
[i
] = displayString
.mid(startIdx
, idx
-startIdx
);
216 * Remaining string; note that there's one more display string than
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
);
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
;
270 result
.second
.templateArgs
= args
;
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
)
288 // split off the template name
289 result
.front().truncate(i
);
292 // look for the next comma or the closing '>', skipping nested '<>'
295 for (; unsigned(i
) < t
.length() && nest
>= 0; i
++)
299 else if (t
[i
] == '>')
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
);
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
])
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
])
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;
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;
365 unsigned penalty
= ~(~0U>>1); // 1 in the leading bit
366 while (equal
&& p
!= pat
.end())
369 accumPenalty
|= penalty
; // penalize wildcards
372 ++p
, ++t
, penalty
>>= 1;
376 if (accumPenalty
== 0)
377 return i
->second
.type
;
378 if (accumPenalty
< minPenalty
) {
379 result
= i
->second
.type
;
380 minPenalty
= accumPenalty
;
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
);