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 <QStandardPaths>
12 #include <kconfiggroup.h>
18 //! the TypeTables of all known libraries
19 static std::list
<TypeTable
> typeTables
;
20 bool typeTablesInited
= false;
23 //! an indentifier for wchar_t
24 TypeInfo
TypeInfo::m_wchartType("");
26 TypeInfo
TypeInfo::m_unknownType("");
29 void TypeTable::initTypeLibraries()
31 if (!typeTablesInited
) {
32 TypeTable::loadTypeTables();
36 void TypeTable::loadTypeTables()
38 typeTablesInited
= true;
40 std::map
<QString
,QString
> files
;
41 for (const QString
& dir
: QStandardPaths::locateAll(QStandardPaths::AppDataLocation
, "types",
42 QStandardPaths::LocateDirectory
))
44 for (const QString
& file
: QDir(dir
).entryList(QStringList() << QStringLiteral("*.kdbgtt")))
46 files
.emplace(file
, dir
);
47 // this did not insert the entry if the same file name occurred earlier
48 // this is exactly what we want: earlier files have higher priority
53 TRACE("no type tables found");
57 for (const auto& file
: files
) {
58 typeTables
.push_back(TypeTable());
59 typeTables
.back().loadFromFile(file
.second
+ '/' + file
.first
);
64 TypeTable::TypeTable()
68 TypeTable::~TypeTable()
73 static const char TypeTableGroup
[] = "Type Table";
74 static const char LibDisplayName
[] = "LibDisplayName";
75 static const char ShlibRE
[] = "ShlibRE";
76 static const char EnableBuiltin
[] = "EnableBuiltin";
77 static const char PrintQStringCmd
[] = "PrintQStringCmd";
78 static const char TypesEntryFmt
[] = "Types%d";
79 static const char DisplayEntry
[] = "Display";
80 static const char AliasEntry
[] = "Alias";
81 static const char TemplateEntry
[] = "Template";
82 static const char ExprEntryFmt
[] = "Expr%d";
83 static const char FunctionGuardEntryFmt
[] = "FunctionGuard%d";
86 void TypeTable::loadFromFile(const QString
& fileName
)
88 TRACE("reading file " + fileName
);
89 KConfig
confFile(fileName
, KConfig::SimpleConfig
);
92 * Read library name and properties.
94 KConfigGroup cf
= confFile
.group(TypeTableGroup
);
95 m_displayName
= cf
.readEntry(LibDisplayName
);
96 if (m_displayName
.isEmpty()) {
97 // use file name instead
98 QFileInfo
fi(fileName
);
99 m_displayName
= fi
.completeBaseName();
102 m_shlibNameRE
= QRegExp(cf
.readEntry(ShlibRE
));
103 m_enabledBuiltins
= cf
.readEntry(EnableBuiltin
, QStringList());
105 QString printQString
= cf
.readEntry(PrintQStringCmd
);
106 m_printQStringDataCmd
= printQString
.toLatin1();
109 * Get the types. We search for entries of kind Types1, Types2, etc.
110 * because a single entry Types could get rather long for large
114 for (int i
= 1; ; i
++) {
115 // next bunch of types
116 KConfigGroup cf
= confFile
.group(TypeTableGroup
);
117 typesEntry
.sprintf(TypesEntryFmt
, i
);
118 if (!cf
.hasKey(typesEntry
))
121 QStringList typeNames
= cf
.readEntry(typesEntry
, QStringList());
125 for (QStringList::iterator it
= typeNames
.begin(); it
!= typeNames
.end(); ++it
)
127 KConfigGroup cf
= confFile
.group(*it
);
128 // check if this is an alias
129 alias
= cf
.readEntry(AliasEntry
);
130 if (alias
.isEmpty()) {
133 // look up the alias type and insert it
134 TypeInfoMap::iterator i
= m_typeDict
.find(alias
);
135 if (i
== m_typeDict
.end()) {
136 TRACE(*it
+ ": alias " + alias
+ " not found");
138 m_aliasDict
.insert(std::make_pair(*it
, &i
->second
));
139 TRACE(*it
+ ": alias " + alias
);
146 void TypeTable::readType(const KConfigGroup
& cf
, const QString
& type
)
148 // the display string
149 QString expr
= cf
.readEntry(DisplayEntry
);
152 if (info
.m_numExprs
== 0) {
153 TRACE("bogus type " + type
+ ": no %% in Display: " + expr
);
157 info
.m_templatePattern
= cf
.readEntry(TemplateEntry
);
159 // Expr1, Expr2, etc...
161 QString funcGuardEntry
;
162 for (int j
= 0; j
< info
.m_numExprs
; j
++)
164 exprEntry
.sprintf(ExprEntryFmt
, j
+1);
165 expr
= cf
.readEntry(exprEntry
);
166 info
.m_exprStrings
[j
] = expr
;
168 funcGuardEntry
.sprintf(FunctionGuardEntryFmt
, j
+1);
169 expr
= cf
.readEntry(funcGuardEntry
);
170 info
.m_guardStrings
[j
] = expr
;
174 if (info
.m_templatePattern
.indexOf('<') < 0)
175 m_typeDict
.insert(std::make_pair(type
, info
));
177 m_templates
.insert(std::make_pair(type
, info
));
178 TRACE(type
+ QString().sprintf(": %d exprs", info
.m_numExprs
));
181 void TypeTable::copyTypes(TypeInfoRefMap
& dict
)
183 for (TypeInfoMap::iterator i
= m_typeDict
.begin(); i
!= m_typeDict
.end(); ++i
) {
184 dict
.insert(std::make_pair(i
->first
, &i
->second
));
186 std::copy(m_aliasDict
.begin(), m_aliasDict
.end(),
187 std::inserter(dict
, dict
.begin()));
190 bool TypeTable::isEnabledBuiltin(const QString
& feature
) const
192 return m_enabledBuiltins
.indexOf(feature
) >= 0;
195 TypeInfo::TypeInfo(const QString
& displayString
)
197 // decompose the input into the parts
201 while (i
< typeInfoMaxExpr
&&
202 (idx
= displayString
.indexOf('%', startIdx
)) >= 0)
204 m_displayString
[i
] = displayString
.mid(startIdx
, idx
-startIdx
);
210 * Remaining string; note that there's one more display string than
213 m_displayString
[i
] = displayString
.right(displayString
.length()-startIdx
);
216 TypeInfo::~TypeInfo()
221 ProgramTypeTable::ProgramTypeTable() :
222 m_parseQt2QStrings(false),
223 m_QCharIsShort(false),
224 m_printQStringDataCmd(0)
228 ProgramTypeTable::~ProgramTypeTable()
232 void ProgramTypeTable::loadTypeTable(TypeTable
* table
)
234 table
->copyTypes(m_types
);
237 const TypeTable::TypeInfoMap
& t
= table
->templates();
238 std::transform(t
.begin(), t
.end(),
239 std::inserter(m_templates
, m_templates
.begin()),
240 std::ptr_fun(template2Info
));
242 // check whether to enable builtin QString support
243 if (!m_parseQt2QStrings
) {
244 m_parseQt2QStrings
= table
->isEnabledBuiltin("QString::Data");
246 if (!m_QCharIsShort
) {
247 m_QCharIsShort
= table
->isEnabledBuiltin("QCharIsShort");
249 if (m_printQStringDataCmd
.isEmpty()) {
250 m_printQStringDataCmd
= table
->printQStringDataCmd();
254 ProgramTypeTable::TemplateMap::value_type
255 ProgramTypeTable::template2Info(const TypeTable::TypeInfoMap::value_type
& tt
)
257 QStringList args
= splitTemplateArgs(tt
.second
.m_templatePattern
);
259 TemplateMap::value_type
result(args
.front(), TemplateInfo());
260 result
.second
.type
= &tt
.second
;
262 result
.second
.templateArgs
= args
;
267 * Splits the name \a t into the template name and its arguments.
268 * The first entry of the returned list is the template name, the remaining
269 * entries are the arguments.
271 QStringList
ProgramTypeTable::splitTemplateArgs(const QString
& t
)
276 int i
= t
.indexOf('<');
280 // split off the template name
281 result
.front().truncate(i
);
284 // look for the next comma or the closing '>', skipping nested '<>'
287 for (; i
< t
.length() && nest
>= 0; i
++)
291 else if (t
[i
] == '>')
293 else if (nest
== 0 && t
[i
] == ',') {
294 // found end of argument
295 QString arg
= t
.mid(start
, i
-start
);
296 result
.push_back(arg
);
297 start
= i
+1; // skip ','
300 // accept the template only if the closing '>' is the last character
301 if (nest
< 0 && i
== t
.length()) {
302 QString arg
= t
.mid(start
, i
-start
-1);
303 result
.push_back(arg
);
311 const TypeInfo
* ProgramTypeTable::lookup(QString type
)
314 * Registered aliases contain the complete template parameter list.
315 * Check for an alias first so that this case is out of the way.
317 if (const TypeInfo
* result
= m_aliasDict
[type
])
321 * Check for a normal type. Even if type is a template instance,
322 * it could have been registered as a normal type instead of a pattern.
324 if (const TypeInfo
* result
= m_types
[type
])
328 * The hard part: Look up a template.
330 QStringList parts
= splitTemplateArgs(type
);
331 if (parts
.size() == 1)
332 return 0; // not a template
334 // We can have several patterns for the same template name.
335 std::pair
<TemplateMap::const_iterator
, TemplateMap::const_iterator
> range
=
336 m_templates
.equal_range(parts
.front());
337 // We pick the one that has the wildcards in the later parameters.
338 unsigned minPenalty
= ~0U;
339 const TypeInfo
* result
= 0;
342 for (TemplateMap::const_iterator i
= range
.first
; i
!= range
.second
; ++i
)
344 const QStringList
& pat
= i
->second
.templateArgs
;
345 if (parts
.size() < pat
.size())
346 continue; // too few arguments
348 // a "*" in the last position of the pattern matches all arguments
349 // at the end of the template's arguments
350 if (parts
.size() > pat
.size() && pat
.back() != "*")
351 continue; // too many arguments and no wildcard
353 QStringList::const_iterator t
= parts
.begin();
354 QStringList::const_iterator p
= pat
.begin();
355 unsigned accumPenalty
= 0;
357 unsigned penalty
= ~(~0U>>1); // 1 in the leading bit
358 while (equal
&& p
!= pat
.end())
361 accumPenalty
|= penalty
; // penalize wildcards
364 ++p
, ++t
, penalty
>>= 1;
368 if (accumPenalty
== 0)
369 return i
->second
.type
;
370 if (accumPenalty
< minPenalty
) {
371 result
= i
->second
.type
;
372 minPenalty
= accumPenalty
;
379 void ProgramTypeTable::registerAlias(const QString
& name
, const TypeInfo
* type
)
381 ASSERT(lookup(name
) == 0 || lookup(name
) == type
);
382 m_aliasDict
.insert(std::make_pair(name
, type
));
385 void ProgramTypeTable::loadLibTypes(const QStringList
& libs
)
387 for (QStringList::const_iterator it
= libs
.begin(); it
!= libs
.end(); ++it
)
389 // look up the library
390 for (std::list
<TypeTable
>::iterator t
= typeTables
.begin(); t
!= typeTables
.end(); ++t
)
392 if (t
->matchFileName(*it
))
394 TRACE("adding types for " + *it
);