My old project for strange attractors
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
This repo is archived. You can view files and clone it, but cannot push or open issues/pull-requests.

273 lines
7.4 KiB

14 years ago
/*
Copyright (c) 2009 Maurice Bos and Nick Overdijk
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* The names of the authors may not be used to endorse or promote
products derived from this software without specific prior written
permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- Maurice Bos (maurice@bosbyte.nl)
- Nick Overdijk (nick@dotsimplicity.net)
*/
#include <iostream>
#include <fstream>
#include <map>
#include <string>
#include <typeinfo>
#include "stf.hpp"
namespace stfu {
std::ostream& operator<< (std::ostream& out, const node& root) {
root.write(out);
return out;
}
bool operator<< (const char* filename, const node& root) {
return root.write(filename);
}
std::istream& operator>> (std::istream& in, node& root) {
root.read(in);
return in;
14 years ago
}
bool operator>> (const char* filename, node& root) {
return root.read(filename);
}
const std::string& node::getValue(const std::string& name, size_t index) const throw(std::out_of_range) {
return get_indexed<std::string, std::string>(values, name, index);
}
/*Function is const, but shouldn't be called on const objects since it returns a nonconst-reference to a member*/
std::string& node::getValue(const std::string& name, size_t index) throw(std::out_of_range) {
return get_indexed<std::string, std::string>(values, name, index);
}
std::string& node::addValue(const std::string& name) {
return values.insert(std::pair<std::string, std::string>(name, std::string()))->second;
}
std::string& node::value(const std::string& name, size_t index) {
try {
return getValue(name, index);
} catch(std::out_of_range& e) {
//it doesn't exist: create it
return addValue(name);
}
}
void node::removeValue(const std::string& name, size_t index) throw(std::out_of_range) {
values.erase(get_indexed_it(values, name, index));
return;
}
void node::renameValue(const std::string& oldName, const std::string& newName, size_t index) {
addValue(newName) = value(oldName, index);
removeValue(oldName, index);
}
const node& node::getChild(const std::string& name, size_t index) const throw(std::out_of_range) {
return get_indexed<std::string, node>(children, name, index);
}
node& node::getChild(const std::string& name, size_t index) throw(std::out_of_range) {
return get_indexed<std::string, node>(children, name, index);
}
node& node::addChild(const std::string& name) {
return children.insert(std::pair<std::string, node>(name, node()))->second;
}
node& node::addChild(const std::string& name, node& newNode) {
return children.insert(std::pair<std::string, node>(name, newNode))->second;
}
node& node::child(const std::string& name, size_t index) {
//if there's no such child, add one
try {
return getChild(name, index);
} catch(std::out_of_range& e) {
//it doesn't exist: create it
return addChild(name);
}
}
void node::renameChild(const std::string& oldName, const std::string& newName, size_t index) {
node copy = child(oldName, index);
removeChild(oldName, index);
addChild(newName) = copy;
}
void node::removeChild(const std::string& name, size_t index) throw(std::out_of_range) {
children.erase(get_indexed_it(children, name, index));
return;
}
bool node::read(const char* filename) {
std::ifstream f(filename);
if(!f.good()) return false;
bool success = read(f);
f.close();
return success;
}
bool node::read(std::istream& in) {
while(1) {
in >> std::ws; //Skip whitespace
//if end of node is reached, return
if(in.peek() == '}') {
in.ignore();
return true;
}
if(in.eof()) {
return true; //End of the file is reached
}
std::string name;
char type; // '{' or '"'
streamRead(in, name, ':'); //Read name (all chars before ':')
type = streamSkip(in,"\"{"); //Skip everything until '{' or '"'
switch(type) {
//in case of value
case '"': {
std::string value;
while(1) {
if(streamRead(in, value, '"') == 0) { //Read to the closing-"
return false;
}
if(in.peek() == '"') {
in.ignore();
value += '"';
continue;
} else {
break;
}
}
this->values.insert(std::pair<std::string,std::string>(name, value));
break;
}
//in case of child
case '{': {
node sub;
if(!sub.read(in)) { //Recursively read the subnode
return false;
}
this->children.insert(std::pair<std::string,node>(name,sub));
break;
}
default:
return false;
}
}
}
/*Writes to a file using it's overloaded self*/
bool node::write(const char* filename) const {
std::ofstream f(filename);
if(!f.good()) {
return false;
}
bool success = write(f);
f.close();
return success;
}
// TODO (Nick#1#): Make write() not put unnamed values on a new line, children are okay.
bool node::write(std::ostream& out, size_t depth, std::string indent) const {
std::string indentation;
for(size_t i = 0; i < depth; i++) {
indentation += indent;
}
for(std::multimap<std::string, std::string>::const_iterator value_it = values.begin(); value_it != values.end(); value_it++) {
//Escape all the '"' by adding a second '"'
std::string value(value_it->second);
size_t found = value.find('"');
//while there are more ", insert second "s
while(found != value.npos) {
value.insert(found, 1, '"');
found = value.find('"', found+2);
}
out << indentation << value_it->first << ": \"" << value << '"' << std::endl;
}
for(std::multimap<std::string, node>::const_iterator child_it = children.begin(); child_it != children.end(); child_it++) {
out << indentation << child_it->first << ": {" << std::endl;
child_it->second.write(out, depth+1);
out << indentation << '}' << std::endl;
}
return true;
}
char node::streamSkip(std::istream& in, const std::string& delimiters) {
char cur;
//Return if the current char is part of delimiters[]
while(in >> std::noskipws >> cur) {
if(delimiters.find_first_of(cur) != delimiters.npos) return cur;
}
return 0;
}
char node::streamRead(std::istream& in, std::string& out, const std::string& delimiters) {
char cur;
//Return if the current char is part of delimiters[]
while(in >> std::noskipws >> cur) {
if(delimiters.find(cur) != delimiters.npos) return cur;
out += cur;
}
return 0;
}
char node::streamRead(std::istream& in, std::string& out, const char delimiter) {
char cur;
//Return if the current char is delimiter
while(in >> std::noskipws >> cur) {
if(delimiter == cur) return cur;
out += cur;
}
return 0;
}
}