Skip to content

Commit

Permalink
libdeng2|Info: Retain letter case in identifiers
Browse files Browse the repository at this point in the history
While block types are still forced to lower case, all element names
now retain their case. They are indexed case insensitively, though,
and looking up elements by name is also case insensitive.

This improves use of Info for scripting, as one can use mixed-case
identifiers without restrictions.
  • Loading branch information
skyjake committed Mar 28, 2014
1 parent d84c1bd commit 66899f0
Show file tree
Hide file tree
Showing 3 changed files with 32 additions and 14 deletions.
31 changes: 23 additions & 8 deletions doomsday/libdeng2/include/de/data/info.h
Expand Up @@ -29,12 +29,15 @@ namespace de {

/**
* Key/value tree. The tree is parsed from the "Snowberry" Info file format.
* @ingroup data
*
* All element names (key identifiers, block names, etc.) are case insensitive, although
* their case is preserved when parsing the tree.
*
* See the Doomsday Wiki for an example of the syntax:
* http://dengine.net/dew/index.php?title=Info
*
* This implementation is based on a C++ port of cfparser.py from Snowberry.
* @ingroup data
*
* @todo Should use de::Lex internally.
*/
Expand Down Expand Up @@ -97,7 +100,12 @@ class DENG2_PUBLIC Info

DENG2_AS_IS_METHODS()

void setName(String const &name) { _name = name.toLower(); }
void setName(String const &name) { _name = name; }

/// Convenience for case-insensitively checking if the name matches @a name.
bool isName(String const &name) const {
return !_name.compareWithoutCase(name);
}

virtual ValueList values() const = 0;

Expand Down Expand Up @@ -151,9 +159,9 @@ class DENG2_PUBLIC Info
};

/**
* Contains other Elements, including other block elements. In addition to
* a name, each block may have a "block type", which is a case insensitive
* identifier.
* Contains other Elements, including other block elements. In addition to a name,
* each block may have a "block type", which is a lower case identifier (always
* forced to lower case).
*/
class DENG2_PUBLIC BlockElement : public Element {
public:
Expand Down Expand Up @@ -189,7 +197,7 @@ class DENG2_PUBLIC Info

int size() const { return _contents.size(); }

bool contains(String const &name) { return _contents.contains(name); }
bool contains(String const &name) { return _contents.contains(name.toLower()); }

void setBlockType(String const &bType) { _blockType = bType.toLower(); }

Expand Down Expand Up @@ -226,7 +234,7 @@ class DENG2_PUBLIC Info
private:
Info &_info;
String _blockType;
Contents _contents;
Contents _contents; // indexed in lower case
ContentsInOrder _contentsInOrder;
};

Expand Down Expand Up @@ -272,12 +280,19 @@ class DENG2_PUBLIC Info

BlockElement const &root() const;

/**
* Finds an element by its path. Info paths use a colon ':' as separator.
*
* @param path Path of element (case insensitive).
*
* @return Element, or @c NULL.
*/
Element const *findByPath(String const &path) const;

/**
* Finds the value of a key.
*
* @param key Key to find.
* @param key Key to find (case insensitive).
* @param value The value is returned here.
*
* @return @c true, if the key was found and @a value is valid. If @c
Expand Down
4 changes: 2 additions & 2 deletions doomsday/libdeng2/src/data/info.cpp
Expand Up @@ -599,13 +599,13 @@ void Info::BlockElement::add(Info::Element *elem)
_contentsInOrder.append(elem); // owned
if(!elem->name().isEmpty())
{
_contents.insert(elem->name(), elem); // not owned (name may be empty)
_contents.insert(elem->name().toLower(), elem); // not owned (name may be empty)
}
}

Info::Element *Info::BlockElement::find(String const &name) const
{
Contents::const_iterator found = _contents.find(name);
Contents::const_iterator found = _contents.find(name.toLower());
if(found == _contents.end()) return 0;
return found.value();
}
Expand Down
11 changes: 7 additions & 4 deletions doomsday/tests/test_info/test_info.dei
Expand Up @@ -71,9 +71,12 @@ group font {
}
}

# Identifiers are all case insensitive.
Font "Title" inherits font.default {
Size: 24pt
Weight $: if __this__.weight == "normal": "bold"; else: "normal"
# Identifiers retain case in script namespaces (and are case
# sensitive), however group types are forced lower case (FoNt==font).
FoNt "Title" inherits font.Default {
SIZE: 24pt
weight $: if __this__.weight == "normal": "bold"; else: "normal"
}
}

script { print "Title font:\n", font.Title }

0 comments on commit 66899f0

Please sign in to comment.