Skip to content

Commit

Permalink
libdeng2: Added a C wrapper for de::Info
Browse files Browse the repository at this point in the history
Simplified interface for querying key values.
  • Loading branch information
skyjake committed Apr 22, 2012
1 parent ea787e0 commit aeb6107
Show file tree
Hide file tree
Showing 4 changed files with 136 additions and 10 deletions.
10 changes: 10 additions & 0 deletions doomsday/libdeng2/include/de/c_wrapper.h
Expand Up @@ -96,6 +96,16 @@ DENG2_PUBLIC void LegacyNetwork_SocketSet_Add(int set, int socket);
DENG2_PUBLIC void LegacyNetwork_SocketSet_Remove(int set, int socket);
DENG2_PUBLIC int LegacyNetwork_SocketSet_Activity(int set);

/*
* Info
*/
DENG2_OPAQUE(Info)

DENG2_PUBLIC Info* Info_NewFromString(const char* utf8text);
DENG2_PUBLIC Info* Info_NewFromFile(const char* nativePath);
DENG2_PUBLIC void Info_Delete(Info* info);
DENG2_PUBLIC int Info_FindValue(Info* info, const char* path, char* buffer, size_t bufSize);

#ifdef __cplusplus
} // extern "C"
#endif
Expand Down
33 changes: 27 additions & 6 deletions doomsday/libdeng2/include/de/data/info.h
Expand Up @@ -96,9 +96,7 @@ class Info
class ListElement : public Element {
public:
ListElement(const String& name) : Element(List, name) {}

void add(const String& v) { _values << v; }

QStringList values() const { return _values; }

private:
Expand All @@ -117,13 +115,21 @@ class Info
typedef QHash<String, Element*> Contents;
typedef QList<Element*> ContentsInOrder;

public:
BlockElement(const String& bType, const String& name) : Element(Block, name) {
setBlockType(bType);
}
~BlockElement();

/**
* The root block is the only one that does not have a block type.
*/
bool isRootBlock() const { return _blockType.isEmpty(); }

const String& blockType() const { return _blockType; }

const ContentsInOrder& contentsInOrder() const { return _contentsInOrder; }

const Contents& contents() const { return _contents; }

QStringList values() const {
Expand All @@ -132,10 +138,13 @@ class Info
}

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

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

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

void clear();

void add(Element* elem) {
DENG2_ASSERT(elem != 0);
_contentsInOrder.append(elem);
Expand All @@ -160,6 +169,17 @@ class Info
return static_cast<KeyElement*>(e)->value();
}

/**
* Looks for an element based on a path where a colon ':' is used to
* separate element names. Whitespace before and after a separator is
* ignored.
*
* @param path Name path.
*
* @return The located element, or @c NULL.
*/
Element* findByPath(const String& path) const;

private:
String _blockType;
Contents _contents;
Expand All @@ -172,18 +192,19 @@ class Info

public:
Info();
~Info();

/**
* Deserializes the key/value data from text.
* Parses the Info contents from a text string.
*
* @param infoSource Info text.
*/
Info(const String& infoSource);

~Info();
void parse(const String& infoSource);

const BlockElement& root() const;

const Element* findByPath(const String& path) const;

private:
struct Instance;
Instance* d;
Expand Down
59 changes: 58 additions & 1 deletion doomsday/libdeng2/src/c_wrapper.cpp
Expand Up @@ -24,6 +24,8 @@
#include "de/ByteRefArray"
#include "de/Block"
#include "de/LogBuffer"
#include "de/Info"
#include <QFile>
#include <cstring>
#include <stdarg.h>

Expand All @@ -39,7 +41,8 @@ void LegacyCore_Delete(LegacyCore* lc)
if(lc)
{
// It gets stopped automatically.
delete reinterpret_cast<de::LegacyCore*>(lc);
DENG2_SELF(LegacyCore, lc);
delete self;
}
}

Expand Down Expand Up @@ -252,3 +255,57 @@ int LegacyNetwork_SocketSet_Activity(int set)
if(!set) return 0;
return DENG2_LEGACYNETWORK().checkSetForActivity(set);
}

Info* Info_NewFromString(const char* utf8text)
{
try
{
QScopedPointer<de::Info> self(new de::Info);
self->parse(QString::fromUtf8(utf8text));
return reinterpret_cast<Info*>(self.take());
}
catch(de::Error& er)
{
LOG_WARNING(er.asText());
}
return 0;
}

Info* Info_NewFromFile(const char* nativePath)
{
QFile file(nativePath);
if(file.open(QFile::ReadOnly | QFile::Text))
{
return Info_NewFromString(file.readAll().constData());
}
return 0;
}

void Info_Delete(Info* info)
{
if(info)
{
DENG2_SELF(Info, info);
delete self;
}
}

int Info_FindValue(Info* info, const char* path, char* buffer, size_t bufSize)
{
if(!info) return false;

DENG2_SELF(Info, info);
const de::Info::Element* element = self->findByPath(path);
if(!element->isKey()) return false;
QString value = static_cast<const de::Info::KeyElement*>(element)->value();
if(buffer)
{
qstrncpy(buffer, value.toUtf8().constData(), bufSize);
return true;
}
else
{
// Just return the size of the value.
return value.size();
}
}
44 changes: 41 additions & 3 deletions doomsday/libdeng2/src/data/info.cpp
Expand Up @@ -450,18 +450,56 @@ void Info::BlockElement::clear()
_contentsInOrder.clear();
}

Info::Info(const String& infoSource)
Info::Element* Info::BlockElement::findByPath(const String &path) const
{
String name;
String remainder;
int pos = path.indexOf(':');
if(pos >= 0)
{
name = path.left(pos);
remainder = path.right(pos + 1);
}
else
{
name = path;
}
name.trimmed();

// Does this element exist?
Element* e = find(name);
if(!e) return 0;

if(e->isBlock())
{
// Descend into sub-blocks.
return static_cast<BlockElement*>(e)->findByPath(remainder);
}
return e;
}

Info::Info()
{
d = new Instance;
d->parse(infoSource);
}

Info::~Info()
{
delete d;
}

const Info::BlockElement &Info::root() const
void Info::parse(const String &infoSource)
{
d->parse(infoSource);
}

const Info::BlockElement& Info::root() const
{
return d->rootBlock;
}

const Info::Element* Info::findByPath(const String &path) const
{
if(path.isEmpty()) return &d->rootBlock;
return d->rootBlock.findByPath(path);
}

0 comments on commit aeb6107

Please sign in to comment.