I put this off for quite a bit, but I got it working now. This is the third re-write. Enjoy!
KaosScript.h
#ifndef KaosScript_h
#define KaosScript_h
#include <vector>
#include <string>
#include <sstream>
using namespace std;
#define MAX_LINE_LENGTH 512
class KaosScript
{
public:
class KaosBlock
{
private:
string type;
string name;
vector<string> value_names;
vector<string> values;
public:
KaosBlock();
string GetType();
string GetName();
string GetString(string ValueName);
int GetInteger(string ValueName);
float GetFloat(string ValueName);
vector<string> GetValueNames();
vector<string> GetValues();
void SetTypeAndName(string Type, string Name);
void InjectValue(string Name, string Value);
};
private:
vector<KaosBlock*> kaos_blocks;
public:
KaosScript(string FileName);
vector<KaosBlock*> GetBlocks();
vector<KaosBlock*> GetBlocksByType(string SelectedType);
vector<KaosBlock*> GetBlocksByName(string SelectedName);
KaosBlock* GetFirstBlockOfType(string SelectedType);
KaosBlock* GetFirstBlock(string SelectedName);
};
#endif
KaosScript.cpp
#include "KaosScript.h"
#include <fstream>
KaosScript::KaosBlock::KaosBlock()
{
type = ""; name = "";
}
string KaosScript::KaosBlock::GetType()
{
return type;
}
string KaosScript::KaosBlock::GetName()
{
return name;
}
string KaosScript::KaosBlock::GetString(string ValueName)
{
for (unsigned int i = 0; i < values.size(); i++)
{
if (value_names[i] == ValueName)
{
return values[i];
}
}
return "";
}
int KaosScript::KaosBlock::GetInteger(string ValueName)
{
for (unsigned int i = 0; i < values.size(); i++)
{
if (value_names[i] == ValueName)
{
int return_val;
stringstream buf;
buf << values[i];
buf >> return_val;
return return_val;
}
}
return 0;
}
float KaosScript::KaosBlock::GetFloat(string ValueName)
{
for (unsigned int i = 0; i < values.size(); i++)
{
if (value_names[i] == ValueName)
{
float return_val;
stringstream buf;
buf << values[i];
buf >> return_val;
return return_val;
}
}
return 0.0f;
}
vector<string> KaosScript::KaosBlock::GetValueNames()
{
return value_names;
}
vector<string> KaosScript::KaosBlock::GetValues()
{
return values;
}
void KaosScript::KaosBlock::SetTypeAndName(string Type, string Name)
{
type = Type; name = Name;
}
void KaosScript::KaosBlock::InjectValue(string Name, string Value)
{
value_names.push_back(Name);
values.push_back(Value);
}
KaosScript::KaosScript(string FileName)
{
string buf;
vector<string> lines;
ifstream new_file(FileName.c_str());
char *buffer = new char[MAX_LINE_LENGTH];
while (!new_file.eof())
{
new_file.getline(buffer, MAX_LINE_LENGTH);
buf = buffer;
lines.push_back(buf);
}
delete[] buffer;
int CurrentBlock = 0;
string curchar = "";
for (unsigned int line = 0; line < lines.size(); line++)//loops through each line
{
for (unsigned int i = 0; i < lines[line].length(); i++)//loops through each char
{
curchar = lines[line].at(i);
if (curchar == "=") //this means something is declared on this line
{
string name = lines[line].substr(0, i);
string value = lines[line].substr(i + 1);
kaos_blocks[CurrentBlock]->InjectValue(name, value);
}
else if (curchar == "{") //this means a block is opening
{
KaosBlock *NewBlock = new KaosBlock();
kaos_blocks.push_back(NewBlock);
int separator = lines[line].find(":");
string type = lines[line].substr(1, separator - 1);
string name = lines[line].substr(separator + 1);
kaos_blocks[CurrentBlock]->SetTypeAndName(type, name);
}
else if (curchar == "}")
{
CurrentBlock++;
}
}
}
}
vector<KaosScript::KaosBlock *> KaosScript::GetBlocks()
{
return kaos_blocks;
}
vector<KaosScript::KaosBlock *> KaosScript::GetBlocksByType(string SelectedType)
{
vector<KaosBlock *> tmp;
for (unsigned int i = 0; i < kaos_blocks.size(); i++)
{
if (kaos_blocks[i]->GetType() == SelectedType)
{
tmp.push_back(kaos_blocks[i]);
}
}
return tmp;
}
vector<KaosScript::KaosBlock *> KaosScript::GetBlocksByName(string SelectedName)
{
vector<KaosBlock *> tmp;
for (unsigned int i = 0; i < kaos_blocks.size(); i++)
{
if (kaos_blocks[i]->GetName() == SelectedName)
{
tmp.push_back(kaos_blocks[i]);
}
}
return tmp;
}
KaosScript::KaosBlock * KaosScript::GetFirstBlockOfType(string SelectedType)
{
for (unsigned int i = 0; i < kaos_blocks.size(); i++)
{
if (kaos_blocks[i]->GetType() == SelectedType)
{
return kaos_blocks[i];
}
}
return NULL;
}
KaosScript::KaosBlock * KaosScript::GetFirstBlock(string SelectedName)
{
for (unsigned int i = 0; i < kaos_blocks.size(); i++)
{
if (kaos_blocks[i]->GetName() == SelectedName)
{
return kaos_blocks[i];
}
}
return NULL;
}
Value names must be unique, but everything else can share names. Since that example explains the syntax, I don't need to say much more, but that it is solely line-based, so you can't have multiple statements per line, sorry.
I've thought of several uses, especially as a world saving type format. You make a block for each object in your world, and then load it.
Lines cannot be longer than 512 characters, but you can change that in KaosScript.h, the #define for MAX_LINE_LENGTH.
KaosScript is also loosely typed. Everything is a string until you cast the value. I don't know what happens if you cast a value with letters to an int or float, though. Probably turns to the ASCII values or something.
My next project is a world editor, saving to .kaos files.
Example - in my FPS's format (called Kaos, which KaosScript was made for), loads the player, a plane to stand on, and a box to push around.
{STATICOBJECT:plane
PositionX=0
PositionY=0
PositionZ=0
Mesh=StandardPlane
Width=512
Length=512
}
{PLAYER:Player1
PositionX=0
PositionY=1.125
PositionZ=0
Angle=90
Mesh=testplayer.x
}
{DYNAMICOBJECT:box
PositionX=20
PositionY=2.5
PositionZ=20
Mesh=StandardCube
Size=5
}
This probably won't work with "vanilla" KaosScript. I mean, it will, but it won't do anything, since KaosScript is just a data formatting language. It's very flexible, though, and it's more like XML than anything (not syntatically.)
--------------------------------------------
New: C++ Usage Example
This is an excerpt from my game engine, it's not DarkGDK, but that doesn't apply to this.
void CApplication::load_settings()
{
KaosScript settings_script("cfg/XarxesSettings.kaos");
settings.Fullscreen = settings_script.GetFirstBlock("WindowSettings")->GetInteger("bFullscreen");
settings.ScreenWidth = settings_script.GetFirstBlock("WindowSettings")->GetInteger("iScreenWidth");
settings.ScreenHeight = settings_script.GetFirstBlock("WindowSettings")->GetInteger("iScreenHeight");
}
"settings" is a struct containing three values indicating whether it's fullscreen or not, and the screen resolution.
Here's the relevant part of the .kaos file, "cfg/XarxesSettings.kaos".
{:WindowsSettings
bFullscreen=1
iScreenWidth=1024
iScreenHeight=768
}
As you can see, the block type isn't necessary. Neither is the block name, but then, how else would you find it?