mirror of
https://github.com/bsnes-emu/bsnes.git
synced 2025-08-22 10:53:05 +02:00
Update to v106r54 release.
byuu says: Changes to hiro will break all but the GTK target. Not that it matters much given that the only ruby drivers that function are all on BSD anyway. But if you are fortunate enough to be able to run this ... you'll find lots of polishing improvements to the bsnes GUI. I posted some screenshots on Twitter, if anyone were interested.
This commit is contained in:
@@ -234,6 +234,20 @@ template<> struct stringify<const view<string>&> {
|
||||
const view<string>& _view;
|
||||
};
|
||||
|
||||
template<> struct stringify<string_pascal> {
|
||||
stringify(const string_pascal& source) : _text(source) {}
|
||||
auto data() const -> const char* { return _text.data(); }
|
||||
auto size() const -> uint { return _text.size(); }
|
||||
const string_pascal& _text;
|
||||
};
|
||||
|
||||
template<> struct stringify<const string_pascal&> {
|
||||
stringify(const string_pascal& source) : _text(source) {}
|
||||
auto data() const -> const char* { return _text.data(); }
|
||||
auto size() const -> uint { return _text.size(); }
|
||||
const string_pascal& _text;
|
||||
};
|
||||
|
||||
//pointers
|
||||
|
||||
template<typename T> struct stringify<T*> {
|
||||
|
@@ -2,6 +2,15 @@
|
||||
|
||||
namespace nall {
|
||||
|
||||
auto string::contains(view<string> characters) const -> maybe<uint> {
|
||||
for(uint x : range(size())) {
|
||||
for(char y : characters) {
|
||||
if(operator[](x) == y) return x;
|
||||
}
|
||||
}
|
||||
return nothing;
|
||||
}
|
||||
|
||||
template<bool Insensitive, bool Quoted> auto string::_find(int offset, view<string> source) const -> maybe<uint> {
|
||||
if(source.size() == 0) return nothing;
|
||||
|
||||
|
@@ -40,7 +40,7 @@ protected:
|
||||
p += length;
|
||||
}
|
||||
|
||||
auto parseData(const char*& p) -> void {
|
||||
auto parseData(const char*& p, view<string> spacing) -> void {
|
||||
if(*p == '=' && *(p + 1) == '\"') {
|
||||
uint length = 2;
|
||||
while(p[length] && p[length] != '\n' && p[length] != '\"') length++;
|
||||
@@ -56,13 +56,13 @@ protected:
|
||||
} else if(*p == ':') {
|
||||
uint length = 1;
|
||||
while(p[length] && p[length] != '\n') length++;
|
||||
_value = {slice(p, 1, length - 1), "\n"};
|
||||
_value = {slice(p, 1, length - 1).trimLeft(spacing, 1L), "\n"};
|
||||
p += length;
|
||||
}
|
||||
}
|
||||
|
||||
//read all attributes for a node
|
||||
auto parseAttributes(const char*& p) -> void {
|
||||
auto parseAttributes(const char*& p, view<string> spacing) -> void {
|
||||
while(*p && *p != '\n') {
|
||||
if(*p != ' ') throw "Invalid node name";
|
||||
while(*p == ' ') p++; //skip excess spaces
|
||||
@@ -73,31 +73,31 @@ protected:
|
||||
while(valid(p[length])) length++;
|
||||
if(length == 0) throw "Invalid attribute name";
|
||||
node->_name = slice(p, 0, length);
|
||||
node->parseData(p += length);
|
||||
node->parseData(p += length, spacing);
|
||||
node->_value.trimRight("\n", 1L);
|
||||
_children.append(node);
|
||||
}
|
||||
}
|
||||
|
||||
//read a node and all of its child nodes
|
||||
auto parseNode(const vector<string>& text, uint& y) -> void {
|
||||
auto parseNode(const vector<string>& text, uint& y, view<string> spacing) -> void {
|
||||
const char* p = text[y++];
|
||||
_metadata = parseDepth(p);
|
||||
parseName(p);
|
||||
parseData(p);
|
||||
parseAttributes(p);
|
||||
parseData(p, spacing);
|
||||
parseAttributes(p, spacing);
|
||||
|
||||
while(y < text.size()) {
|
||||
uint depth = readDepth(text[y]);
|
||||
if(depth <= _metadata) break;
|
||||
|
||||
if(text[y][depth] == ':') {
|
||||
_value.append(slice(text[y++], depth + 1), "\n");
|
||||
_value.append(slice(text[y++], depth + 1).trimLeft(spacing, 1L), "\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
SharedNode node(new ManagedNode);
|
||||
node->parseNode(text, y);
|
||||
node->parseNode(text, y, spacing);
|
||||
_children.append(node);
|
||||
}
|
||||
|
||||
@@ -105,7 +105,7 @@ protected:
|
||||
}
|
||||
|
||||
//read top-level nodes
|
||||
auto parse(string document) -> void {
|
||||
auto parse(string document, view<string> spacing) -> void {
|
||||
//in order to simplify the parsing logic; we do an initial pass to normalize the data
|
||||
//the below code will turn '\r\n' into '\n'; skip empty lines; and skip comment lines
|
||||
char* p = document.get(), *output = p;
|
||||
@@ -134,37 +134,37 @@ protected:
|
||||
uint y = 0;
|
||||
while(y < text.size()) {
|
||||
SharedNode node(new ManagedNode);
|
||||
node->parseNode(text, y);
|
||||
node->parseNode(text, y, spacing);
|
||||
if(node->_metadata > 0) throw "Root nodes cannot be indented";
|
||||
_children.append(node);
|
||||
}
|
||||
}
|
||||
|
||||
friend auto unserialize(const string&) -> Markup::Node;
|
||||
friend auto unserialize(const string&, view<string>) -> Markup::Node;
|
||||
};
|
||||
|
||||
inline auto unserialize(const string& markup) -> Markup::Node {
|
||||
inline auto unserialize(const string& markup, view<string> spacing = {}) -> Markup::Node {
|
||||
SharedNode node(new ManagedNode);
|
||||
try {
|
||||
node->parse(markup);
|
||||
node->parse(markup, spacing);
|
||||
} catch(const char* error) {
|
||||
node.reset();
|
||||
}
|
||||
return (Markup::SharedNode&)node;
|
||||
}
|
||||
|
||||
inline auto serialize(const Markup::Node& node, uint depth = 0) -> string {
|
||||
inline auto serialize(const Markup::Node& node, view<string> spacing = {}, uint depth = 0) -> string {
|
||||
if(!node.name()) {
|
||||
string result;
|
||||
for(auto leaf : node) {
|
||||
result.append(serialize(leaf, depth));
|
||||
result.append(serialize(leaf, spacing, depth));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
string padding;
|
||||
padding.resize(depth * 2);
|
||||
for(auto& byte : padding) byte = ' ';
|
||||
padding.fill(' ');
|
||||
|
||||
vector<string> lines;
|
||||
if(auto value = node.value()) lines = value.split("\n");
|
||||
@@ -172,16 +172,16 @@ inline auto serialize(const Markup::Node& node, uint depth = 0) -> string {
|
||||
string result;
|
||||
result.append(padding);
|
||||
result.append(node.name());
|
||||
if(lines.size() == 1) result.append(":", lines[0]);
|
||||
if(lines.size() == 1) result.append(":", spacing, lines[0]);
|
||||
result.append("\n");
|
||||
if(lines.size() > 1) {
|
||||
padding.append(" ");
|
||||
for(auto& line : lines) {
|
||||
result.append(padding, ":", line, "\n");
|
||||
result.append(padding, ":", spacing, line, "\n");
|
||||
}
|
||||
}
|
||||
for(auto leaf : node) {
|
||||
result.append(serialize(leaf, depth + 1));
|
||||
result.append(serialize(leaf, spacing, depth + 1));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
79
nall/string/pascal.hpp
Normal file
79
nall/string/pascal.hpp
Normal file
@@ -0,0 +1,79 @@
|
||||
#pragma once
|
||||
|
||||
namespace nall {
|
||||
|
||||
struct string_pascal {
|
||||
using type = string_pascal;
|
||||
|
||||
string_pascal(const char* text = nullptr) {
|
||||
if(text && *text) {
|
||||
uint size = strlen(text);
|
||||
_data = memory::allocate<char>(sizeof(uint) + size + 1);
|
||||
((uint*)_data)[0] = size;
|
||||
memory::copy(_data + sizeof(uint), text, size);
|
||||
_data[sizeof(uint) + size] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
string_pascal(const string& text) {
|
||||
if(text.size()) {
|
||||
_data = memory::allocate<char>(sizeof(uint) + text.size() + 1);
|
||||
((uint*)_data)[0] = text.size();
|
||||
memory::copy(_data + sizeof(uint), text.data(), text.size());
|
||||
_data[sizeof(uint) + text.size()] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
string_pascal(const string_pascal& source) { operator=(source); }
|
||||
string_pascal(string_pascal&& source) { operator=(move(source)); }
|
||||
|
||||
~string_pascal() {
|
||||
if(_data) memory::free(_data);
|
||||
}
|
||||
|
||||
explicit operator bool() const { return _data; }
|
||||
operator const char*() const { return _data ? _data + sizeof(uint) : nullptr; }
|
||||
operator string() const { return _data ? string{_data + sizeof(uint)} : ""; }
|
||||
|
||||
auto operator=(const string_pascal& source) -> type& {
|
||||
if(this == &source) return *this;
|
||||
if(_data) { memory::free(_data); _data = nullptr; }
|
||||
if(source._data) {
|
||||
uint size = source.size();
|
||||
_data = memory::allocate<char>(sizeof(uint) + size);
|
||||
memory::copy(_data, source._data, sizeof(uint) + size);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
auto operator=(string_pascal&& source) -> type& {
|
||||
if(this == &source) return *this;
|
||||
if(_data) memory::free(_data);
|
||||
_data = source._data;
|
||||
source._data = nullptr;
|
||||
return *this;
|
||||
}
|
||||
|
||||
auto operator==(view<string> source) const -> bool {
|
||||
return size() == source.size() && memory::compare(data(), source.data(), size()) == 0;
|
||||
}
|
||||
|
||||
auto operator!=(view<string> source) const -> bool {
|
||||
return size() != source.size() || memory::compare(data(), source.data(), size()) != 0;
|
||||
}
|
||||
|
||||
auto data() const -> char* {
|
||||
if(!_data) return nullptr;
|
||||
return _data + sizeof(uint);
|
||||
}
|
||||
|
||||
auto size() const -> uint {
|
||||
if(!_data) return 0;
|
||||
return ((uint*)_data)[0];
|
||||
}
|
||||
|
||||
protected:
|
||||
char* _data = nullptr;
|
||||
};
|
||||
|
||||
}
|
Reference in New Issue
Block a user