mirror of https://github.com/bsnes-emu/bsnes.git
Update to v094r37 release.
byuu says: Changelog: - synchronizes lots of nall changes - changes displayed program title from tomoko to higan(*) - browser dialog sort is case-insensitive - .sys folders look at user-selected library path; no longer hard-coded Tried to get rid of the file modes from the Windows browser dialog, but it was being a bitch so I left it on for now. - The storage locations and binary still use tomoko. I'm not really sure what to do here. The idea is there may be more than one "higan" UI in the future, but I don't want people to go around calling the entire program by the UI name. For official Windows releases, I can rename the binaries to "higan-{profile}.exe", and by putting the config files with the binary, they won't ever see the tomoko folder. Linux is of course trickier. Note: Windows users will need to edit hiro/components.hpp and comment out these lines: #define Hiro_Console #define Hiro_IconView #define Hiro_SourceView #define Hiro_TreeView I forgot to do that, and too lazy to upload another WIP.
This commit is contained in:
parent
ecb35cac33
commit
092cac9073
|
@ -8,7 +8,7 @@ using namespace nall;
|
|||
|
||||
namespace Emulator {
|
||||
static const string Name = "higan";
|
||||
static const string Version = "094.36";
|
||||
static const string Version = "094.37";
|
||||
static const string Author = "byuu";
|
||||
static const string License = "GPLv3";
|
||||
static const string Website = "http://byuu.org/";
|
||||
|
|
|
@ -50,22 +50,22 @@
|
|||
#define Hiro_CheckButton
|
||||
#define Hiro_CheckLabel
|
||||
#define Hiro_ComboButton
|
||||
//#define Hiro_Console
|
||||
#define Hiro_Console
|
||||
#define Hiro_Frame
|
||||
#define Hiro_HexEdit
|
||||
#define Hiro_HorizontalScroller
|
||||
#define Hiro_HorizontalSlider
|
||||
//#define Hiro_IconView
|
||||
#define Hiro_IconView
|
||||
#define Hiro_Label
|
||||
#define Hiro_LineEdit
|
||||
#define Hiro_ListView
|
||||
#define Hiro_ProgressBar
|
||||
#define Hiro_RadioButton
|
||||
#define Hiro_RadioLabel
|
||||
//#define Hiro_SourceView
|
||||
#define Hiro_SourceView
|
||||
#define Hiro_TabFrame
|
||||
#define Hiro_TextEdit
|
||||
//#define Hiro_TreeView
|
||||
#define Hiro_TreeView
|
||||
#define Hiro_VerticalScroller
|
||||
#define Hiro_VerticalSlider
|
||||
#define Hiro_Viewport
|
||||
|
|
|
@ -124,7 +124,7 @@ auto BrowserDialogWindow::run() -> lstring {
|
|||
view.setBatchable(state.action == "openFiles").onActivate([&] { activate(); }).onChange([&] { change(); });
|
||||
filterList.setVisible(state.action != "selectFolder").onChange([&] { setPath(state.path); });
|
||||
for(auto& filter : state.filters) {
|
||||
auto part = filter.split<1>("|");
|
||||
auto part = filter.split("|", 1L);
|
||||
filterList.append(ComboButtonItem().setText(part.first()));
|
||||
}
|
||||
fileName.setVisible(state.action == "saveFile").onActivate([&] { accept(); });
|
||||
|
@ -136,7 +136,7 @@ auto BrowserDialogWindow::run() -> lstring {
|
|||
|
||||
if(!state.filters) state.filters.append("All|*");
|
||||
for(auto& filter : state.filters) {
|
||||
auto part = filter.split<1>("|");
|
||||
auto part = filter.split("|", 1L);
|
||||
filters.append(part.last().split(":"));
|
||||
}
|
||||
|
||||
|
@ -165,7 +165,7 @@ auto BrowserDialogWindow::setPath(string path) -> void {
|
|||
view.append(ListViewColumn().setExpandable());
|
||||
view.append(ListViewColumn().setForegroundColor({192, 128, 128}));
|
||||
|
||||
auto contents = directory::contents(path);
|
||||
auto contents = directory::icontents(path);
|
||||
bool folderMode = state.action == "openFolder";
|
||||
|
||||
for(auto content : contents) {
|
||||
|
@ -175,7 +175,7 @@ auto BrowserDialogWindow::setPath(string path) -> void {
|
|||
|
||||
view.append(ListViewItem()
|
||||
.append(ListViewCell().setText(content).setIcon(Icon::Emblem::Folder))
|
||||
.append(ListViewCell().setText(octal<3>(storage::mode({path, content}) & 0777)))
|
||||
.append(ListViewCell().setText(octal(storage::mode({path, content}) & 0777, 3L)))
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -186,7 +186,7 @@ auto BrowserDialogWindow::setPath(string path) -> void {
|
|||
|
||||
view.append(ListViewItem()
|
||||
.append(ListViewCell().setText(content).setIcon(folderMode ? Icon::Action::Open : Icon::Emblem::File))
|
||||
.append(ListViewCell().setText(octal<3>(storage::mode({path, content}) & 0777)))
|
||||
.append(ListViewCell().setText(octal(storage::mode({path, content}) & 0777, 3L)))
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@ static void BrowserWindow_addFilters(GtkWidget* dialog, lstring filters) {
|
|||
for(auto& filter : filters) {
|
||||
GtkFileFilter* gtkFilter = gtk_file_filter_new();
|
||||
gtk_file_filter_set_name(gtkFilter, filter);
|
||||
lstring patterns = filter.split<1>("(")(1).rtrim(")").split(",").strip();
|
||||
lstring patterns = filter.split("(", 1L)(1).rtrim(")", 1L).split(",").strip();
|
||||
for(auto& pattern : patterns) gtk_file_filter_add_pattern(gtkFilter, pattern);
|
||||
gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(dialog), gtkFilter);
|
||||
}
|
||||
|
|
|
@ -27,7 +27,7 @@ auto pFont::size(string font, string text) -> Size {
|
|||
}
|
||||
|
||||
auto pFont::create(string description) -> PangoFontDescription* {
|
||||
lstring part = description.split<2>(",").strip();
|
||||
lstring part = description.split(",", 2L).strip();
|
||||
|
||||
string family = "Sans";
|
||||
unsigned size = 8u;
|
||||
|
|
|
@ -122,7 +122,7 @@ auto pHexEdit::update() -> void {
|
|||
string output;
|
||||
unsigned offset = state().offset;
|
||||
for(auto row : range(state().rows)) {
|
||||
output.append(hex<8>(offset));
|
||||
output.append(hex(offset, 8L));
|
||||
output.append(" ");
|
||||
|
||||
string hexdata;
|
||||
|
@ -130,7 +130,7 @@ auto pHexEdit::update() -> void {
|
|||
for(auto column : range(state().columns)) {
|
||||
if(offset < state().length) {
|
||||
uint8_t data = self().doRead(offset++);
|
||||
hexdata.append(hex<2>(data));
|
||||
hexdata.append(hex(data, 2L));
|
||||
hexdata.append(" ");
|
||||
ansidata.append(data >= 0x20 && data <= 0x7e ? (char)data : '.');
|
||||
} else {
|
||||
|
|
|
@ -23,7 +23,7 @@ Size pFont::size(string font, string text) {
|
|||
}
|
||||
|
||||
QFont pFont::create(string description) {
|
||||
lstring part = description.split<2>(",").strip();
|
||||
lstring part = description.split(",", 2L).strip();
|
||||
|
||||
string family = "Sans";
|
||||
unsigned size = 8u;
|
||||
|
|
|
@ -21,7 +21,7 @@ static auto BrowserWindow_fileDialog(bool save, BrowserWindow::State& state) ->
|
|||
for(auto& filter : state.filters) {
|
||||
lstring part = filter.split("(");
|
||||
if(part.size() != 2) continue;
|
||||
part[1].rtrim(")");
|
||||
part[1].rtrim(")", 1L);
|
||||
part[1].replace(" ", "");
|
||||
part[1].transform(",", ";");
|
||||
filters.append(filter, "\t", part[1], "\t");
|
||||
|
|
|
@ -28,7 +28,7 @@ auto pFont::size(const string& font, const string& text) -> Size {
|
|||
}
|
||||
|
||||
auto pFont::create(const string& description) -> HFONT {
|
||||
lstring part = description.split<2>(",").strip();
|
||||
lstring part = description.split(",", 2L).strip();
|
||||
|
||||
string family = "Tahoma";
|
||||
unsigned size = 8u;
|
||||
|
|
|
@ -122,7 +122,7 @@ auto pHexEdit::update() -> void {
|
|||
string output;
|
||||
unsigned offset = state().offset;
|
||||
for(auto row : range(state().rows)) {
|
||||
output.append(hex<8>(offset));
|
||||
output.append(hex(offset, 8L));
|
||||
output.append(" ");
|
||||
|
||||
string hexdata;
|
||||
|
@ -130,7 +130,7 @@ auto pHexEdit::update() -> void {
|
|||
for(auto column : range(state().columns)) {
|
||||
if(offset < state().length) {
|
||||
uint8_t data = self().doRead(offset++);
|
||||
hexdata.append(hex<2>(data));
|
||||
hexdata.append(hex(data, 2L));
|
||||
hexdata.append(" ");
|
||||
ansidata.append(data >= 0x20 && data <= 0x7e ? (char)data : '.');
|
||||
} else {
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
|
||||
namespace nall {
|
||||
|
||||
constexpr inline uintmax_t binary_(const char* s, uintmax_t sum = 0) {
|
||||
constexpr inline auto binary_(const char* s, uintmax_t sum = 0) -> uintmax_t {
|
||||
return (
|
||||
*s == '0' || *s == '1' ? binary_(s + 1, (sum << 1) | *s - '0') :
|
||||
*s == '\'' ? binary_(s + 1, sum) :
|
||||
|
@ -13,7 +13,7 @@ constexpr inline uintmax_t binary_(const char* s, uintmax_t sum = 0) {
|
|||
);
|
||||
}
|
||||
|
||||
constexpr inline uintmax_t octal_(const char* s, uintmax_t sum = 0) {
|
||||
constexpr inline auto octal_(const char* s, uintmax_t sum = 0) -> uintmax_t {
|
||||
return (
|
||||
*s >= '0' && *s <= '7' ? octal_(s + 1, (sum << 3) | *s - '0') :
|
||||
*s == '\'' ? octal_(s + 1, sum) :
|
||||
|
@ -21,7 +21,7 @@ constexpr inline uintmax_t octal_(const char* s, uintmax_t sum = 0) {
|
|||
);
|
||||
}
|
||||
|
||||
constexpr inline uintmax_t decimal_(const char* s, uintmax_t sum = 0) {
|
||||
constexpr inline auto decimal_(const char* s, uintmax_t sum = 0) -> uintmax_t {
|
||||
return (
|
||||
*s >= '0' && *s <= '9' ? decimal_(s + 1, (sum * 10) + *s - '0') :
|
||||
*s == '\'' ? decimal_(s + 1, sum) :
|
||||
|
@ -29,7 +29,7 @@ constexpr inline uintmax_t decimal_(const char* s, uintmax_t sum = 0) {
|
|||
);
|
||||
}
|
||||
|
||||
constexpr inline uintmax_t hex_(const char* s, uintmax_t sum = 0) {
|
||||
constexpr inline auto hex_(const char* s, uintmax_t sum = 0) -> uintmax_t {
|
||||
return (
|
||||
*s >= 'A' && *s <= 'F' ? hex_(s + 1, (sum << 4) | *s - 'A' + 10) :
|
||||
*s >= 'a' && *s <= 'f' ? hex_(s + 1, (sum << 4) | *s - 'a' + 10) :
|
||||
|
@ -41,7 +41,7 @@ constexpr inline uintmax_t hex_(const char* s, uintmax_t sum = 0) {
|
|||
|
||||
//
|
||||
|
||||
constexpr inline uintmax_t binary(const char* s) {
|
||||
constexpr inline auto binary(const char* s) -> uintmax_t {
|
||||
return (
|
||||
*s == '0' && *(s + 1) == 'B' ? binary_(s + 2) :
|
||||
*s == '0' && *(s + 1) == 'b' ? binary_(s + 2) :
|
||||
|
@ -50,7 +50,7 @@ constexpr inline uintmax_t binary(const char* s) {
|
|||
);
|
||||
}
|
||||
|
||||
constexpr inline uintmax_t octal(const char* s) {
|
||||
constexpr inline auto octal(const char* s) -> uintmax_t {
|
||||
return (
|
||||
*s == '0' && *(s + 1) == 'O' ? octal_(s + 2) :
|
||||
*s == '0' && *(s + 1) == 'o' ? octal_(s + 2) :
|
||||
|
@ -58,7 +58,7 @@ constexpr inline uintmax_t octal(const char* s) {
|
|||
);
|
||||
}
|
||||
|
||||
constexpr inline intmax_t integer(const char* s) {
|
||||
constexpr inline auto integer(const char* s) -> intmax_t {
|
||||
return (
|
||||
*s == '+' ? +decimal_(s + 1) :
|
||||
*s == '-' ? -decimal_(s + 1) :
|
||||
|
@ -66,13 +66,13 @@ constexpr inline intmax_t integer(const char* s) {
|
|||
);
|
||||
}
|
||||
|
||||
constexpr inline uintmax_t decimal(const char* s) {
|
||||
constexpr inline auto decimal(const char* s) -> uintmax_t {
|
||||
return (
|
||||
decimal_(s)
|
||||
);
|
||||
}
|
||||
|
||||
constexpr inline uintmax_t hex(const char* s) {
|
||||
constexpr inline auto hex(const char* s) -> uintmax_t {
|
||||
return (
|
||||
*s == '0' && *(s + 1) == 'X' ? hex_(s + 2) :
|
||||
*s == '0' && *(s + 1) == 'x' ? hex_(s + 2) :
|
||||
|
@ -81,7 +81,7 @@ constexpr inline uintmax_t hex(const char* s) {
|
|||
);
|
||||
}
|
||||
|
||||
inline double real(const char* s) {
|
||||
inline auto real(const char* s) -> double {
|
||||
return atof(s);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,84 +1,123 @@
|
|||
#ifndef NALL_BEAT_ARCHIVE_HPP
|
||||
#define NALL_BEAT_ARCHIVE_HPP
|
||||
|
||||
#include <nall/beat/base.hpp>
|
||||
#include <nall/beat/file.hpp>
|
||||
|
||||
namespace nall {
|
||||
namespace nall { namespace Beat {
|
||||
|
||||
struct beatArchive : beatBase {
|
||||
bool create(const string& beatname, string pathname, const string& metadata = "") {
|
||||
if(fp.open(beatname, file::mode::write) == false) return false;
|
||||
if(pathname.endsWith("/") == false) pathname.append("/");
|
||||
struct Archive {
|
||||
static auto create(const string& beatname, const string& pathname, const string& metadata = "") -> bool;
|
||||
static auto unpack(const string& beatname, const string& pathname) -> bool;
|
||||
static auto extract(const string& beatname, const string& pathname) -> vector<uint8_t>;
|
||||
|
||||
checksum.reset();
|
||||
writeString("BPA1");
|
||||
writeNumber(metadata.length());
|
||||
writeString(metadata);
|
||||
|
||||
lstring list;
|
||||
ls(list, pathname, pathname);
|
||||
for(auto &name : list) {
|
||||
if(name.endsWith("/")) {
|
||||
name.rtrim("/");
|
||||
writeNumber(0 | ((name.length() - 1) << 1));
|
||||
writeString(name);
|
||||
} else {
|
||||
file stream;
|
||||
if(stream.open({pathname, name}, file::mode::read) == false) return false;
|
||||
writeNumber(1 | ((name.length() - 1) << 1));
|
||||
writeString(name);
|
||||
unsigned size = stream.size();
|
||||
writeNumber(size);
|
||||
Hash::CRC32 checksum;
|
||||
while(size--) {
|
||||
uint8_t data = stream.read();
|
||||
write(data);
|
||||
checksum.data(data);
|
||||
}
|
||||
writeChecksum(checksum.value());
|
||||
}
|
||||
}
|
||||
|
||||
writeChecksum(checksum.value());
|
||||
fp.close();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool unpack(const string& beatname, string pathname) {
|
||||
if(fp.open(beatname, file::mode::read) == false) return false;
|
||||
if(pathname.endsWith("/") == false) pathname.append("/");
|
||||
|
||||
checksum.reset();
|
||||
if(readString(4) != "BPA1") return false;
|
||||
unsigned length = readNumber();
|
||||
while(length--) read();
|
||||
|
||||
directory::create(pathname);
|
||||
while(fp.offset() < fp.size() - 4) {
|
||||
unsigned data = readNumber();
|
||||
string name = readString((data >> 1) + 1);
|
||||
if(name.find("\\") || name.find("../")) return false; //block path exploits
|
||||
|
||||
if((data & 1) == 0) {
|
||||
directory::create({pathname, name});
|
||||
} else {
|
||||
file stream;
|
||||
if(stream.open({pathname, name}, file::mode::write) == false) return false;
|
||||
unsigned size = readNumber();
|
||||
Hash::CRC32 checksum;
|
||||
while(size--) {
|
||||
uint8_t data = read();
|
||||
stream.write(data);
|
||||
checksum.data(data);
|
||||
}
|
||||
if(readChecksum(checksum.value()) == false) return false;
|
||||
}
|
||||
}
|
||||
|
||||
return readChecksum(checksum.value());
|
||||
}
|
||||
private:
|
||||
static auto scan(lstring& result, const string& basename, const string& pathname) -> void;
|
||||
};
|
||||
|
||||
auto Archive::create(const string& beatname, const string& pathname, const string& metadata) -> bool {
|
||||
if(!beatname.endsWith(".bpa") || !pathname.endsWith("/")) return false; //protect against reversed arguments
|
||||
|
||||
File beat{beatname, file::mode::write};
|
||||
if(!beat) return false; //file not writable?
|
||||
|
||||
beat.writes("BPA1");
|
||||
beat.writevu(metadata.size());
|
||||
beat.writes(metadata);
|
||||
|
||||
lstring contents;
|
||||
scan(contents, pathname, pathname);
|
||||
|
||||
for(auto& name : contents) {
|
||||
if(name.endsWith("/")) {
|
||||
name.rtrim("/");
|
||||
beat.writevu(0 | ((name.length() - 1) << 1));
|
||||
beat.writes(name);
|
||||
} else {
|
||||
File input{{pathname, name}, file::mode::read};
|
||||
if(!input) return false;
|
||||
|
||||
beat.writevu(1 | ((name.length() - 1) << 1));
|
||||
beat.writes(name);
|
||||
auto size = input.size();
|
||||
beat.writevu(size);
|
||||
while(size--) beat.write(input.read());
|
||||
beat.writel(input.checksum.value(), 4);
|
||||
}
|
||||
}
|
||||
|
||||
beat.writel(beat.checksum.value(), 4);
|
||||
return true;
|
||||
}
|
||||
|
||||
auto Archive::unpack(const string& beatname, const string& pathname) -> bool {
|
||||
if(!beatname.endsWith(".bpa") || !pathname.endsWith("/")) return false; //protect against reversed arguments
|
||||
|
||||
File beat{beatname, file::mode::read};
|
||||
if(!beat) return false; //file not readable?
|
||||
|
||||
if(beat.reads(4) != "BPA1") return false;
|
||||
auto size = beat.readvu();
|
||||
while(size--) beat.read();
|
||||
|
||||
directory::create(pathname);
|
||||
while(beat.offset() < beat.size() - 4) {
|
||||
auto data = beat.readvu();
|
||||
auto name = beat.reads((data >> 1) + 1);
|
||||
if(name.find("\\") || name.find("../")) return false; //block path exploits
|
||||
|
||||
if((data & 1) == 0) {
|
||||
directory::create({pathname, name});
|
||||
} else {
|
||||
File output{{pathname, name}, file::mode::write};
|
||||
if(!output) return false;
|
||||
|
||||
auto size = beat.readvu();
|
||||
while(size--) output.write(beat.read());
|
||||
if(beat.readl(4) != output.checksum.value()) return false;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t checksum = beat.checksum.value();
|
||||
return beat.readl(4) == checksum;
|
||||
}
|
||||
|
||||
auto Archive::extract(const string& beatname, const string& filename) -> vector<uint8_t> {
|
||||
File beat{beatname, file::mode::read};
|
||||
if(!beat) return {}; //file not readable?
|
||||
|
||||
if(beat.reads(4) != "BPA1") return {};
|
||||
auto size = beat.readvu();
|
||||
beat.seek(beat.offset() + size);
|
||||
|
||||
while(beat.offset() < beat.size() - 4) {
|
||||
auto data = beat.readvu();
|
||||
auto name = beat.reads((data >> 1) + 1);
|
||||
if((data & 1) == 0) continue;
|
||||
auto size = beat.readvu();
|
||||
if(name != filename) {
|
||||
beat.seek(beat.offset() + size + 4);
|
||||
continue;
|
||||
}
|
||||
|
||||
vector<uint8_t> result;
|
||||
result.resize(size);
|
||||
beat.checksum.reset();
|
||||
for(auto n : range(size)) result[n] = beat.read();
|
||||
uint32_t checksum = beat.checksum.value();
|
||||
if(beat.readl(4) != checksum) return {};
|
||||
return result;
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
auto Archive::scan(lstring& result, const string& basename, const string& pathname) -> void {
|
||||
for(auto& name : directory::contents(pathname)) {
|
||||
result.append(string{pathname, name}.ltrim(basename, 1L));
|
||||
if(name.endsWith("/")) scan(result, basename, {pathname, name});
|
||||
}
|
||||
}
|
||||
|
||||
}}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,92 +0,0 @@
|
|||
#ifndef NALL_BEAT_BASE_HPP
|
||||
#define NALL_BEAT_BASE_HPP
|
||||
|
||||
namespace nall {
|
||||
|
||||
struct beatBase {
|
||||
protected:
|
||||
file fp;
|
||||
Hash::CRC32 checksum;
|
||||
|
||||
void ls(lstring& list, const string& path, const string& basepath) {
|
||||
lstring paths = directory::folders(path);
|
||||
for(auto& pathname : paths) {
|
||||
list.append(string{path, pathname}.ltrim(basepath));
|
||||
ls(list, {path, pathname}, basepath);
|
||||
}
|
||||
|
||||
lstring files = directory::files(path);
|
||||
for(auto& filename : files) {
|
||||
list.append(string{path, filename}.ltrim(basepath));
|
||||
}
|
||||
}
|
||||
|
||||
void write(uint8_t data) {
|
||||
fp.write(data);
|
||||
checksum.data(data);
|
||||
}
|
||||
|
||||
void writeNumber(uint64_t data) {
|
||||
while(true) {
|
||||
uint64_t x = data & 0x7f;
|
||||
data >>= 7;
|
||||
if(data == 0) return write(0x80 | x);
|
||||
write(x);
|
||||
data--;
|
||||
}
|
||||
}
|
||||
|
||||
void writeString(const string& text) {
|
||||
unsigned length = text.length();
|
||||
for(unsigned n = 0; n < length; n++) write(text[n]);
|
||||
}
|
||||
|
||||
void writeChecksum(uint32_t checksum) {
|
||||
write(checksum >> 0);
|
||||
write(checksum >> 8);
|
||||
write(checksum >> 16);
|
||||
write(checksum >> 24);
|
||||
}
|
||||
|
||||
uint8_t read() {
|
||||
uint8_t data = fp.read();
|
||||
checksum.data(data);
|
||||
return data;
|
||||
}
|
||||
|
||||
uint64_t readNumber() {
|
||||
uint64_t data = 0, shift = 1;
|
||||
while(true) {
|
||||
uint8_t x = read();
|
||||
data += (x & 0x7f) * shift;
|
||||
if(x & 0x80) break;
|
||||
shift <<= 7;
|
||||
data += shift;
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
string readString(unsigned length) {
|
||||
string text;
|
||||
text.resize(length + 1);
|
||||
char* p = text.pointer();
|
||||
while(length--) {
|
||||
*p = fp.read();
|
||||
checksum.data(*p++);
|
||||
}
|
||||
return text;
|
||||
}
|
||||
|
||||
bool readChecksum(uint32_t source) {
|
||||
uint32_t checksum = 0;
|
||||
checksum |= read() << 0;
|
||||
checksum |= read() << 8;
|
||||
checksum |= read() << 16;
|
||||
checksum |= read() << 24;
|
||||
return checksum == source;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,26 @@
|
|||
#ifndef NALL_BEAT_FILE_HPP
|
||||
#define NALL_BEAT_FILE_HPP
|
||||
|
||||
namespace nall { namespace Beat {
|
||||
|
||||
struct File : file {
|
||||
using file::file;
|
||||
auto read() -> uint8_t override;
|
||||
auto write(uint8_t) -> void override;
|
||||
Hash::CRC32 checksum;
|
||||
};
|
||||
|
||||
auto File::read() -> uint8_t {
|
||||
uint8_t data = file::read();
|
||||
checksum.data(data);
|
||||
return data;
|
||||
}
|
||||
|
||||
auto File::write(uint8_t data) -> void {
|
||||
checksum.data(data);
|
||||
return file::write(data);
|
||||
}
|
||||
|
||||
}}
|
||||
|
||||
#endif
|
|
@ -160,13 +160,13 @@ protected:
|
|||
void ls(lstring& list, const string& path, const string& basepath) {
|
||||
lstring paths = directory::folders(path);
|
||||
for(auto& pathname : paths) {
|
||||
list.append(string{path, pathname}.ltrim(basepath));
|
||||
list.append(string{path, pathname}.ltrim(basepath, 1L));
|
||||
ls(list, {path, pathname}, basepath);
|
||||
}
|
||||
|
||||
lstring files = directory::files(path);
|
||||
for(auto& filename : files) {
|
||||
list.append(string{path, filename}.ltrim(basepath));
|
||||
list.append(string{path, filename}.ltrim(basepath, 1L));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
24
nall/bit.hpp
24
nall/bit.hpp
|
@ -5,28 +5,28 @@
|
|||
|
||||
namespace nall {
|
||||
|
||||
template<unsigned bits> inline uintmax_t uclamp(const uintmax_t x) {
|
||||
template<unsigned bits> inline auto uclamp(const uintmax_t x) -> uintmax_t {
|
||||
enum : uintmax_t { b = 1ull << (bits - 1), y = b * 2 - 1 };
|
||||
return y + ((x - y) & -(x < y)); //min(x, y);
|
||||
}
|
||||
|
||||
template<unsigned bits> inline uintmax_t uclip(const uintmax_t x) {
|
||||
template<unsigned bits> inline auto uclip(const uintmax_t x) -> uintmax_t {
|
||||
enum : uintmax_t { b = 1ull << (bits - 1), m = b * 2 - 1 };
|
||||
return (x & m);
|
||||
}
|
||||
|
||||
template<unsigned bits> inline intmax_t sclamp(const intmax_t x) {
|
||||
template<unsigned bits> inline auto sclamp(const intmax_t x) -> intmax_t {
|
||||
enum : intmax_t { b = 1ull << (bits - 1), m = b - 1 };
|
||||
return (x > m) ? m : (x < -b) ? -b : x;
|
||||
}
|
||||
|
||||
template<unsigned bits> inline intmax_t sclip(const intmax_t x) {
|
||||
template<unsigned bits> inline auto sclip(const intmax_t x) -> intmax_t {
|
||||
enum : uintmax_t { b = 1ull << (bits - 1), m = b * 2 - 1 };
|
||||
return ((x & m) ^ b) - b;
|
||||
}
|
||||
|
||||
namespace bit {
|
||||
constexpr inline uintmax_t mask(const char* s, uintmax_t sum = 0) {
|
||||
constexpr inline auto mask(const char* s, uintmax_t sum = 0) -> uintmax_t {
|
||||
return (
|
||||
*s == '0' || *s == '1' ? mask(s + 1, (sum << 1) | 1) :
|
||||
*s == ' ' || *s == '_' ? mask(s + 1, sum) :
|
||||
|
@ -35,7 +35,7 @@ namespace bit {
|
|||
);
|
||||
}
|
||||
|
||||
constexpr inline uintmax_t test(const char* s, uintmax_t sum = 0) {
|
||||
constexpr inline auto test(const char* s, uintmax_t sum = 0) -> uintmax_t {
|
||||
return (
|
||||
*s == '0' || *s == '1' ? test(s + 1, (sum << 1) | (*s - '0')) :
|
||||
*s == ' ' || *s == '_' ? test(s + 1, sum) :
|
||||
|
@ -45,22 +45,22 @@ namespace bit {
|
|||
}
|
||||
|
||||
//lowest(0b1110) == 0b0010
|
||||
constexpr inline uintmax_t lowest(const uintmax_t x) {
|
||||
constexpr inline auto lowest(const uintmax_t x) -> uintmax_t {
|
||||
return x & -x;
|
||||
}
|
||||
|
||||
//clear_lowest(0b1110) == 0b1100
|
||||
constexpr inline uintmax_t clear_lowest(const uintmax_t x) {
|
||||
constexpr inline auto clear_lowest(const uintmax_t x) -> uintmax_t {
|
||||
return x & (x - 1);
|
||||
}
|
||||
|
||||
//set_lowest(0b0101) == 0b0111
|
||||
constexpr inline uintmax_t set_lowest(const uintmax_t x) {
|
||||
constexpr inline auto set_lowest(const uintmax_t x) -> uintmax_t {
|
||||
return x | (x + 1);
|
||||
}
|
||||
|
||||
//count number of bits set in a byte
|
||||
inline unsigned count(uintmax_t x) {
|
||||
inline auto count(uintmax_t x) -> unsigned {
|
||||
unsigned count = 0;
|
||||
do count += x & 1; while(x >>= 1);
|
||||
return count;
|
||||
|
@ -68,7 +68,7 @@ namespace bit {
|
|||
|
||||
//return index of the first bit set (or zero of no bits are set)
|
||||
//first(0b1000) == 3
|
||||
inline unsigned first(uintmax_t x) {
|
||||
inline auto first(uintmax_t x) -> unsigned {
|
||||
unsigned first = 0;
|
||||
while(x) { if(x & 1) break; x >>= 1; first++; }
|
||||
return first;
|
||||
|
@ -76,7 +76,7 @@ namespace bit {
|
|||
|
||||
//round up to next highest single bit:
|
||||
//round(15) == 16, round(16) == 16, round(17) == 32
|
||||
inline uintmax_t round(uintmax_t x) {
|
||||
inline auto round(uintmax_t x) -> uintmax_t {
|
||||
if((x & (x - 1)) == 0) return x;
|
||||
while(x & (x - 1)) x &= x - 1;
|
||||
return x << 1;
|
||||
|
|
|
@ -4,25 +4,20 @@
|
|||
namespace nall {
|
||||
|
||||
struct bitvector {
|
||||
protected:
|
||||
uint8_t* pool = nullptr;
|
||||
unsigned bits = 0;
|
||||
|
||||
public:
|
||||
bitvector() {}
|
||||
bitvector() = default;
|
||||
bitvector(unsigned size) { resize(size); }
|
||||
bitvector(const bitvector& source) { operator=(source); }
|
||||
bitvector(bitvector&& source) { operator=(std::move(source)); }
|
||||
bitvector(bitvector&& source) { operator=(move(source)); }
|
||||
~bitvector() { reset(); }
|
||||
|
||||
bitvector& operator=(const bitvector& source) {
|
||||
auto operator=(const bitvector& source) -> bitvector& {
|
||||
bits = source.bits;
|
||||
pool = (uint8_t*)realloc(pool, bytes());
|
||||
memcpy(pool, source.pool, bytes());
|
||||
pool = (uint8_t*)memory::resize(pool, bytes());
|
||||
memory::copy(pool, source.pool, bytes());
|
||||
return *this;
|
||||
}
|
||||
|
||||
bitvector& operator=(bitvector&& source) {
|
||||
auto operator=(bitvector&& source) -> bitvector& {
|
||||
pool = source.pool;
|
||||
bits = source.bits;
|
||||
source.pool = nullptr;
|
||||
|
@ -31,86 +26,90 @@ public:
|
|||
}
|
||||
|
||||
explicit operator bool() const { return bits > 0; }
|
||||
bool empty() const { return bits == 0; }
|
||||
unsigned size() const { return bits; }
|
||||
unsigned bytes() const { return (bits + 7) / 8; }
|
||||
uint8_t* data() { return pool; }
|
||||
const uint8_t* data() const { return pool; }
|
||||
auto empty() const -> bool { return bits == 0; }
|
||||
auto size() const -> unsigned { return bits; }
|
||||
auto bytes() const -> unsigned { return (bits + 7) / 8; }
|
||||
auto data() -> uint8_t* { return pool; }
|
||||
auto data() const -> const uint8_t* { return pool; }
|
||||
|
||||
void reset() {
|
||||
auto reset() -> void {
|
||||
if(pool) free(pool);
|
||||
pool = nullptr;
|
||||
bits = 0;
|
||||
}
|
||||
|
||||
void resize(unsigned size) {
|
||||
auto resize(unsigned size) -> void {
|
||||
unsigned from = bits;
|
||||
bits = size;
|
||||
for(unsigned n = size; n < from; n++) clear(n); //on reduce
|
||||
pool = (uint8_t*)realloc(pool, bytes());
|
||||
pool = (uint8_t*)memory::resize(pool, bytes());
|
||||
for(unsigned n = from; n < size; n++) clear(n); //on expand
|
||||
}
|
||||
|
||||
bool get(unsigned position) const {
|
||||
auto get(unsigned position) const -> bool {
|
||||
return pool[position >> 3] & (0x80 >> (position & 7));
|
||||
}
|
||||
|
||||
void clear() {
|
||||
memset(pool, 0x00, bytes());
|
||||
auto clear() -> void {
|
||||
memory::fill(pool, bytes(), 0x00);
|
||||
}
|
||||
|
||||
void set() {
|
||||
memset(pool, 0xff, bytes());
|
||||
auto set() -> void {
|
||||
memory::fill(pool, bytes(), 0xff);
|
||||
for(unsigned n = bits; n < bytes() * 8; n++) clear(n);
|
||||
}
|
||||
|
||||
void clear(unsigned position) {
|
||||
auto clear(unsigned position) -> void {
|
||||
pool[position >> 3] &= ~(0x80 >> (position & 7));
|
||||
}
|
||||
|
||||
void set(unsigned position) {
|
||||
auto set(unsigned position) -> void {
|
||||
pool[position >> 3] |= (0x80 >> (position & 7));
|
||||
}
|
||||
|
||||
void invert(unsigned position) {
|
||||
auto invert(unsigned position) -> void {
|
||||
get(position) ? clear(position) : set(position);
|
||||
}
|
||||
|
||||
void set(unsigned position, bool value) {
|
||||
auto set(unsigned position, bool value) -> void {
|
||||
value ? set(position) : clear(position);
|
||||
}
|
||||
|
||||
struct reference {
|
||||
reference(bitvector& self, unsigned position) : self(self), position(position) {}
|
||||
operator bool() const { return self.get(position); }
|
||||
void operator=(bool value) { self.set(position, value); }
|
||||
auto operator=(bool value) -> reference& { self.set(position, value); return *this; }
|
||||
|
||||
protected:
|
||||
bitvector& self;
|
||||
unsigned position;
|
||||
};
|
||||
|
||||
reference operator[](unsigned position) {
|
||||
auto operator[](unsigned position) -> reference {
|
||||
return reference(*this, position);
|
||||
}
|
||||
|
||||
bool operator[](unsigned position) const {
|
||||
auto operator[](unsigned position) const -> bool {
|
||||
return get(position);
|
||||
}
|
||||
|
||||
struct iterator {
|
||||
iterator(bitvector& self, unsigned position) : self(self), position(position) {}
|
||||
bool operator!=(const iterator& source) const { return position != source.position; }
|
||||
iterator& operator++() { position++; return *this; }
|
||||
reference operator*() { return self.operator[](position); }
|
||||
auto operator!=(const iterator& source) const -> bool { return position != source.position; }
|
||||
auto operator++() -> iterator& { position++; return *this; }
|
||||
auto operator*() -> reference { return self.operator[](position); }
|
||||
|
||||
protected:
|
||||
bitvector& self;
|
||||
unsigned position;
|
||||
};
|
||||
|
||||
iterator begin() { return iterator(*this, 0); }
|
||||
iterator end() { return iterator(*this, bits); }
|
||||
auto begin() -> iterator { return iterator(*this, 0); }
|
||||
auto end() -> iterator { return iterator(*this, bits); }
|
||||
|
||||
protected:
|
||||
uint8_t* pool = nullptr;
|
||||
unsigned bits = 0;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -9,11 +9,11 @@
|
|||
namespace nall {
|
||||
|
||||
struct bmp {
|
||||
inline static bool read(const string& filename, uint32_t*& data, unsigned& width, unsigned& height);
|
||||
inline static bool write(const string& filename, const uint32_t* data, unsigned width, unsigned height, unsigned pitch, bool alpha = false);
|
||||
inline static auto read(const string& filename, uint32_t*& data, unsigned& width, unsigned& height) -> bool;
|
||||
inline static auto write(const string& filename, const uint32_t* data, unsigned width, unsigned height, unsigned pitch, bool alpha = false) -> bool;
|
||||
};
|
||||
|
||||
bool bmp::read(const string& filename, uint32_t*& data, unsigned& width, unsigned& height) {
|
||||
auto bmp::read(const string& filename, uint32_t*& data, unsigned& width, unsigned& height) -> bool {
|
||||
file fp;
|
||||
if(fp.open(filename, file::mode::read) == false) return false;
|
||||
if(fp.size() < 0x36) return false;
|
||||
|
@ -55,7 +55,7 @@ bool bmp::read(const string& filename, uint32_t*& data, unsigned& width, unsigne
|
|||
return true;
|
||||
}
|
||||
|
||||
bool bmp::write(const string& filename, const uint32_t* data, unsigned width, unsigned height, unsigned pitch, bool alpha) {
|
||||
auto bmp::write(const string& filename, const uint32_t* data, unsigned width, unsigned height, unsigned pitch, bool alpha) -> bool {
|
||||
file fp;
|
||||
if(fp.open(filename, file::mode::write) == false) return false;
|
||||
|
||||
|
|
|
@ -15,11 +15,11 @@ struct Node {
|
|||
void* data = nullptr;
|
||||
vector<Node> children;
|
||||
|
||||
bool empty() const {
|
||||
auto empty() const -> bool {
|
||||
return data == nullptr;
|
||||
}
|
||||
|
||||
string get() const {
|
||||
auto get() const -> string {
|
||||
switch(type) {
|
||||
case Type::Bool: return {*(bool*)data};
|
||||
case Type::Signed: return {*(signed*)data};
|
||||
|
@ -30,7 +30,7 @@ struct Node {
|
|||
return "";
|
||||
}
|
||||
|
||||
void set(const string& value) {
|
||||
auto set(const string& value) -> void {
|
||||
switch(type) {
|
||||
case Type::Bool: *(bool*)data = (value != "false"); break;
|
||||
case Type::Signed: *(signed*)data = integer(value); break;
|
||||
|
@ -40,15 +40,15 @@ struct Node {
|
|||
}
|
||||
}
|
||||
|
||||
void assign() { type = Type::Null; data = nullptr; }
|
||||
void assign(bool& bind) { type = Type::Bool; data = (void*)&bind; }
|
||||
void assign(signed& bind) { type = Type::Signed; data = (void*)&bind; }
|
||||
void assign(unsigned& bind) { type = Type::Unsigned; data = (void*)&bind; }
|
||||
void assign(double& bind) { type = Type::Double; data = (void*)&bind; }
|
||||
void assign(string& bind) { type = Type::String; data = (void*)&bind; }
|
||||
void assign(const Node& node) { operator=(node); }
|
||||
auto assign() { type = Type::Null; data = nullptr; }
|
||||
auto assign(bool& bind) { type = Type::Bool; data = (void*)&bind; }
|
||||
auto assign(signed& bind) { type = Type::Signed; data = (void*)&bind; }
|
||||
auto assign(unsigned& bind) { type = Type::Unsigned; data = (void*)&bind; }
|
||||
auto assign(double& bind) { type = Type::Double; data = (void*)&bind; }
|
||||
auto assign(string& bind) { type = Type::String; data = (void*)&bind; }
|
||||
auto assign(const Node& node) { operator=(node); }
|
||||
|
||||
template<typename T> void append(T& data, const string& name, const string& desc = "") {
|
||||
template<typename T> auto append(T& data, const string& name, const string& desc = "") -> void {
|
||||
Node node;
|
||||
node.assign(data);
|
||||
node.name = name;
|
||||
|
@ -56,7 +56,7 @@ struct Node {
|
|||
children.append(node);
|
||||
}
|
||||
|
||||
void load(Markup::Node path) {
|
||||
auto load(Markup::Node path) -> void {
|
||||
for(auto& child : children) {
|
||||
if(auto leaf = path[child.name]) {
|
||||
if(!child.empty()) child.set(leaf.text());
|
||||
|
@ -65,7 +65,7 @@ struct Node {
|
|||
}
|
||||
}
|
||||
|
||||
void save(file& fp, unsigned depth = 0) {
|
||||
auto save(file& fp, unsigned depth = 0) -> void {
|
||||
for(auto& child : children) {
|
||||
if(child.desc) {
|
||||
for(unsigned n = 0; n < depth; n++) fp.print(" ");
|
||||
|
@ -82,14 +82,14 @@ struct Node {
|
|||
};
|
||||
|
||||
struct Document : Node {
|
||||
bool load(const string& filename) {
|
||||
auto load(const string& filename) -> bool {
|
||||
if(!file::exists(filename)) return false;
|
||||
auto document = BML::unserialize(string::read(filename));
|
||||
Node::load(document);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool save(const string& filename) {
|
||||
auto save(const string& filename) -> bool {
|
||||
file fp(filename, file::mode::write);
|
||||
if(!fp.open()) return false;
|
||||
Node::save(fp);
|
||||
|
|
|
@ -0,0 +1,274 @@
|
|||
#ifndef NALL_DATABASE_ODBC_HPP
|
||||
#define NALL_DATABASE_ODBC_HPP
|
||||
|
||||
#include <nall/string.hpp>
|
||||
|
||||
#include <sql.h>
|
||||
#include <sqltypes.h>
|
||||
#include <sqlext.h>
|
||||
|
||||
namespace nall { namespace Database {
|
||||
|
||||
struct ODBC {
|
||||
struct Statement {
|
||||
Statement(const Statement& source) = delete;
|
||||
auto operator=(const Statement& source) -> Statement& = delete;
|
||||
|
||||
Statement(SQLHANDLE statement) : _statement(statement) {}
|
||||
Statement(Statement&& source) { operator=(move(source)); }
|
||||
|
||||
auto operator=(Statement&& source) -> Statement& {
|
||||
_statement = source._statement;
|
||||
_output = source._output;
|
||||
source._statement = nullptr;
|
||||
source._output = 0;
|
||||
return *this;
|
||||
}
|
||||
|
||||
auto integer(unsigned column) -> int64_t {
|
||||
int64_t value = 0;
|
||||
SQLGetData(statement(), 1 + column, SQL_C_SBIGINT, &value, 0, nullptr);
|
||||
return value;
|
||||
}
|
||||
|
||||
auto decimal(unsigned column) -> uint64_t {
|
||||
uint64_t value = 0;
|
||||
SQLGetData(statement(), 1 + column, SQL_C_UBIGINT, &value, 0, nullptr);
|
||||
return value;
|
||||
}
|
||||
|
||||
auto real(unsigned column) -> double {
|
||||
double value = 0.0;
|
||||
SQLGetData(statement(), 1 + column, SQL_C_DOUBLE, &value, 0, nullptr);
|
||||
return value;
|
||||
}
|
||||
|
||||
auto text(unsigned column) -> string {
|
||||
string value;
|
||||
value.resize(65535);
|
||||
SQLLEN size = 0;
|
||||
SQLGetData(statement(), 1 + column, SQL_C_CHAR, value.pointer(), value.size(), &size);
|
||||
value.resize(size);
|
||||
return value;
|
||||
}
|
||||
|
||||
auto data(unsigned column) -> vector<uint8_t> {
|
||||
vector<uint8_t> value;
|
||||
value.resize(65535);
|
||||
SQLLEN size = 0;
|
||||
SQLGetData(statement(), 1 + column, SQL_C_CHAR, value.data(), value.size(), &size);
|
||||
value.resize(size);
|
||||
return value;
|
||||
}
|
||||
|
||||
auto integer() -> int64_t { return integer(_output++); }
|
||||
auto decimal() -> uint64_t { return decimal(_output++); }
|
||||
auto real() -> double { return real(_output++); }
|
||||
auto text() -> string { return text(_output++); }
|
||||
auto data() -> vector<uint8_t> { return data(_output++); }
|
||||
|
||||
protected:
|
||||
virtual auto statement() -> SQLHANDLE { return _statement; }
|
||||
|
||||
SQLHANDLE _statement = nullptr;
|
||||
unsigned _output = 0;
|
||||
};
|
||||
|
||||
struct Query : Statement {
|
||||
Query(const Query& source) = delete;
|
||||
auto operator=(const Query& source) -> Query& = delete;
|
||||
|
||||
Query(SQLHANDLE statement) : Statement(statement) {}
|
||||
Query(Query&& source) : Statement(source._statement) { operator=(move(source)); }
|
||||
|
||||
~Query() {
|
||||
if(statement()) {
|
||||
SQLFreeHandle(SQL_HANDLE_STMT, _statement);
|
||||
_statement = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
auto operator=(Query&& source) -> Query& {
|
||||
_bindings = move(source._bindings);
|
||||
_statement = source._statement;
|
||||
_result = source._result;
|
||||
_input = source._input;
|
||||
_stepped = source._stepped;
|
||||
source._statement = nullptr;
|
||||
source._result = SQL_SUCCESS;
|
||||
source._input = 0;
|
||||
source._stepped = false;
|
||||
return *this;
|
||||
}
|
||||
|
||||
//ODBC SQLBindParameter only holds pointers to data values
|
||||
//if the bound paramters go out of scope before the query is executed, binding would reference dangling pointers
|
||||
//so to work around this, we cache all parameters inside Query until the query is executed
|
||||
|
||||
auto& bind(unsigned column, nullptr_t) { return _bindings.append({column, any{(nullptr_t)nullptr}}), *this; }
|
||||
auto& bind(unsigned column, int32_t value) { return _bindings.append({column, any{(int32_t)value}}), *this; }
|
||||
auto& bind(unsigned column, uint32_t value) { return _bindings.append({column, any{(uint32_t)value}}), *this; }
|
||||
auto& bind(unsigned column, int64_t value) { return _bindings.append({column, any{(int64_t)value}}), *this; }
|
||||
auto& bind(unsigned column, uint64_t value) { return _bindings.append({column, any{(uint64_t)value}}), *this; }
|
||||
auto& bind(unsigned column, double value) { return _bindings.append({column, any{(double)value}}), *this; }
|
||||
auto& bind(unsigned column, const string& value) { return _bindings.append({column, any{(string)value}}), *this; }
|
||||
auto& bind(unsigned column, const vector<uint8_t>& value) { return _bindings.append({column, any{(vector<uint8_t>)value}}), *this; }
|
||||
|
||||
auto& bind(nullptr_t) { return bind(_input++, nullptr); }
|
||||
auto& bind(int32_t value) { return bind(_input++, value); }
|
||||
auto& bind(uint32_t value) { return bind(_input++, value); }
|
||||
auto& bind(int64_t value) { return bind(_input++, value); }
|
||||
auto& bind(uint64_t value) { return bind(_input++, value); }
|
||||
auto& bind(double value) { return bind(_input++, value); }
|
||||
auto& bind(const string& value) { return bind(_input++, value); }
|
||||
auto& bind(const vector<uint8_t>& value) { return bind(_input++, value); }
|
||||
|
||||
auto step() -> bool {
|
||||
if(!_stepped) {
|
||||
for(auto& binding : _bindings) {
|
||||
if(binding.value.is<nullptr_t>()) {
|
||||
SQLLEN length = SQL_NULL_DATA;
|
||||
SQLBindParameter(_statement, 1 + binding.column, SQL_PARAM_INPUT, SQL_C_NUMERIC, SQL_NUMERIC, 0, 0, nullptr, 0, &length);
|
||||
} else if(binding.value.is<int32_t>()) {
|
||||
SQLBindParameter(_statement, 1 + binding.column, SQL_PARAM_INPUT, SQL_C_SLONG, SQL_INTEGER, 0, 0, &binding.value.get<int32_t>(), 0, nullptr);
|
||||
} else if(binding.value.is<uint32_t>()) {
|
||||
SQLBindParameter(_statement, 1 + binding.column, SQL_PARAM_INPUT, SQL_C_ULONG, SQL_INTEGER, 0, 0, &binding.value.get<uint32_t>(), 0, nullptr);
|
||||
} else if(binding.value.is<int64_t>()) {
|
||||
SQLBindParameter(_statement, 1 + binding.column, SQL_PARAM_INPUT, SQL_C_SBIGINT, SQL_INTEGER, 0, 0, &binding.value.get<int64_t>(), 0, nullptr);
|
||||
} else if(binding.value.is<uint64_t>()) {
|
||||
SQLBindParameter(_statement, 1 + binding.column, SQL_PARAM_INPUT, SQL_C_UBIGINT, SQL_INTEGER, 0, 0, &binding.value.get<uint64_t>(), 0, nullptr);
|
||||
} else if(binding.value.is<double>()) {
|
||||
SQLBindParameter(_statement, 1 + binding.column, SQL_PARAM_INPUT, SQL_C_DOUBLE, SQL_DOUBLE, 0, 0, &binding.value.get<double>(), 0, nullptr);
|
||||
} else if(binding.value.is<string>()) {
|
||||
SQLLEN length = SQL_NTS;
|
||||
SQLBindParameter(_statement, 1 + binding.column, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_VARCHAR, 0, 0, (SQLPOINTER)binding.value.get<string>().data(), 0, &length);
|
||||
} else if(binding.value.is<vector<uint8_t>>()) {
|
||||
SQLLEN length = binding.value.get<vector<uint8_t>>().size();
|
||||
SQLBindParameter(_statement, 1 + binding.column, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_VARBINARY, 0, 0, (SQLPOINTER)binding.value.get<vector<uint8_t>>().data(), 0, &length);
|
||||
}
|
||||
}
|
||||
|
||||
_stepped = true;
|
||||
_result = SQLExecute(_statement);
|
||||
if(!success()) return false;
|
||||
}
|
||||
|
||||
_result = SQLFetch(_statement);
|
||||
_output = 0;
|
||||
return success();
|
||||
}
|
||||
|
||||
struct Iterator {
|
||||
Iterator(Query& query, bool finished) : query(query), finished(finished) {}
|
||||
auto operator*() -> Statement { return query._statement; }
|
||||
auto operator!=(const Iterator& source) const -> bool { return finished != source.finished; }
|
||||
auto operator++() -> Iterator& { finished = !query.step(); return *this; }
|
||||
|
||||
protected:
|
||||
Query& query;
|
||||
bool finished = false;
|
||||
};
|
||||
|
||||
auto begin() -> Iterator { return Iterator(*this, !step()); }
|
||||
auto end() -> Iterator { return Iterator(*this, true); }
|
||||
|
||||
private:
|
||||
auto success() const -> bool {
|
||||
return _result == SQL_SUCCESS || _result == SQL_SUCCESS_WITH_INFO;
|
||||
}
|
||||
|
||||
auto statement() -> SQLHANDLE override {
|
||||
if(!_stepped) step();
|
||||
return _statement;
|
||||
}
|
||||
|
||||
struct Binding {
|
||||
unsigned column;
|
||||
any value;
|
||||
};
|
||||
vector<Binding> _bindings;
|
||||
|
||||
SQLRETURN _result = SQL_SUCCESS;
|
||||
unsigned _input = 0;
|
||||
bool _stepped = false;
|
||||
};
|
||||
|
||||
ODBC() {
|
||||
_result = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &_environment);
|
||||
if(!success()) return;
|
||||
|
||||
SQLSetEnvAttr(_environment, SQL_ATTR_ODBC_VERSION, (void*)SQL_OV_ODBC3, 0);
|
||||
}
|
||||
|
||||
ODBC(const string& database, const string& username, const string& password) : ODBC() {
|
||||
open(database, username, password);
|
||||
}
|
||||
|
||||
~ODBC() {
|
||||
if(_environment) {
|
||||
close();
|
||||
SQLFreeHandle(SQL_HANDLE_ENV, _environment);
|
||||
_environment = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
explicit operator bool() const { return _connection; }
|
||||
|
||||
auto open(const string& database, const string& username, const string& password) -> bool {
|
||||
if(!_environment) return false;
|
||||
close();
|
||||
|
||||
_result = SQLAllocHandle(SQL_HANDLE_DBC, _environment, &_connection);
|
||||
if(!success()) return false;
|
||||
|
||||
SQLSetConnectAttr(_connection, SQL_LOGIN_TIMEOUT, (SQLPOINTER)5, 0);
|
||||
_result = SQLConnectA(_connection,
|
||||
(SQLCHAR*)database.data(), SQL_NTS,
|
||||
(SQLCHAR*)username.data(), SQL_NTS,
|
||||
(SQLCHAR*)password.data(), SQL_NTS
|
||||
);
|
||||
if(!success()) return close(), false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
auto close() -> void {
|
||||
if(_connection) {
|
||||
SQLDisconnect(_connection);
|
||||
SQLFreeHandle(SQL_HANDLE_DBC, _connection);
|
||||
_connection = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename... P> auto execute(const string& statement, P&&... p) -> Query {
|
||||
if(!_connection) return {nullptr};
|
||||
|
||||
SQLHANDLE _statement = nullptr;
|
||||
_result = SQLAllocHandle(SQL_HANDLE_STMT, _connection, &_statement);
|
||||
if(!success()) return {nullptr};
|
||||
|
||||
Query query{_statement};
|
||||
_result = SQLPrepareA(_statement, (SQLCHAR*)statement.data(), SQL_NTS);
|
||||
if(!success()) return {nullptr};
|
||||
|
||||
bind(query, forward<P>(p)...);
|
||||
return query;
|
||||
}
|
||||
|
||||
private:
|
||||
auto success() const -> bool { return _result == SQL_SUCCESS || _result == SQL_SUCCESS_WITH_INFO; }
|
||||
|
||||
auto bind(Query&) -> void {}
|
||||
template<typename T, typename... P> auto bind(Query& query, const T& value, P&&... p) -> void {
|
||||
query.bind(value);
|
||||
bind(query, forward<P>(p)...);
|
||||
}
|
||||
|
||||
SQLHANDLE _environment = nullptr;
|
||||
SQLHANDLE _connection = nullptr;
|
||||
SQLRETURN _result = SQL_SUCCESS;
|
||||
};
|
||||
|
||||
}}
|
||||
|
||||
#endif
|
|
@ -15,33 +15,38 @@ namespace nall { namespace Database {
|
|||
|
||||
struct SQLite3 {
|
||||
struct Statement {
|
||||
using type = Statement;
|
||||
Statement(const Statement& source) = delete;
|
||||
auto operator=(const Statement& source) -> Statement& = delete;
|
||||
|
||||
Statement(sqlite3_stmt* stmt) : stmt(stmt) {}
|
||||
Statement(const Statement& source) { operator=(source); }
|
||||
Statement(sqlite3_stmt* statement) : _statement(statement) {}
|
||||
Statement(Statement&& source) { operator=(move(source)); }
|
||||
|
||||
auto operator=(const Statement& source) -> type& { stmt = source.stmt, stepped = source.stepped, response = source.response; return *this; }
|
||||
auto operator=(Statement&& source) -> type& { operator=(source); source.stmt = nullptr, source.stepped = false, source.response = SQLITE_OK; return *this; }
|
||||
explicit operator bool() { return !finished(); }
|
||||
auto operator=(Statement&& source) -> Statement& {
|
||||
_statement = source._statement;
|
||||
_response = source._response;
|
||||
_output = source._output;
|
||||
source._statement = nullptr;
|
||||
source._response = SQLITE_OK;
|
||||
source._output = 0;
|
||||
return *this;
|
||||
}
|
||||
|
||||
auto bind(unsigned column, nullptr_t) -> type& { sqlite3_bind_null(stmt, 1 + column); return *this; }
|
||||
auto bind(unsigned column, int32_t value) -> type& { sqlite3_bind_int(stmt, 1 + column, value); return *this; }
|
||||
auto bind(unsigned column, uint32_t value) -> type& { sqlite3_bind_int(stmt, 1 + column, value); return *this; }
|
||||
auto bind(unsigned column, int64_t value) -> type& { sqlite3_bind_int64(stmt, 1 + column, value); return *this; }
|
||||
auto bind(unsigned column, uint64_t value) -> type& { sqlite3_bind_int64(stmt, 1 + column, value); return *this; }
|
||||
auto bind(unsigned column, double value) -> type& { sqlite3_bind_double(stmt, 1 + column, value); return *this; }
|
||||
auto bind(unsigned column, const string& value) -> type& { sqlite3_bind_text(stmt, 1 + column, value.data(), value.size(), SQLITE_TRANSIENT); return *this; }
|
||||
auto bind(unsigned column, const vector<uint8_t>& value) -> type& { sqlite3_bind_blob(stmt, 1 + column, value.data(), value.size(), SQLITE_TRANSIENT); return *this; }
|
||||
auto integer(unsigned column) -> int64_t {
|
||||
return sqlite3_column_int64(statement(), column);
|
||||
}
|
||||
|
||||
auto integer(unsigned column) -> int64_t { return sqlite3_column_int64(handle(), column); }
|
||||
auto decimal(unsigned column) -> uint64_t { return sqlite3_column_int64(handle(), column); }
|
||||
auto real(unsigned column) -> double { return sqlite3_column_double(handle(), column); }
|
||||
auto decimal(unsigned column) -> uint64_t {
|
||||
return sqlite3_column_int64(statement(), column);
|
||||
}
|
||||
|
||||
auto real(unsigned column) -> double {
|
||||
return sqlite3_column_double(statement(), column);
|
||||
}
|
||||
|
||||
auto text(unsigned column) -> string {
|
||||
string result;
|
||||
if(auto text = sqlite3_column_text(handle(), column)) {
|
||||
result.resize(sqlite3_column_bytes(handle(), column));
|
||||
if(auto text = sqlite3_column_text(statement(), column)) {
|
||||
result.resize(sqlite3_column_bytes(statement(), column));
|
||||
memory::copy(result.pointer(), text, result.size());
|
||||
}
|
||||
return result;
|
||||
|
@ -49,109 +54,143 @@ struct SQLite3 {
|
|||
|
||||
auto data(unsigned column) -> vector<uint8_t> {
|
||||
vector<uint8_t> result;
|
||||
if(auto data = sqlite3_column_blob(handle(), column)) {
|
||||
result.resize(sqlite3_column_bytes(handle(), column));
|
||||
if(auto data = sqlite3_column_blob(statement(), column)) {
|
||||
result.resize(sqlite3_column_bytes(statement(), column));
|
||||
memory::copy(result.data(), data, result.size());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
auto integer() -> int64_t { return integer(column++); }
|
||||
auto decimal() -> uint64_t { return decimal(column++); }
|
||||
auto real() -> double { return real(column++); }
|
||||
auto text() -> string { return text(column++); }
|
||||
auto data() -> vector<uint8_t> { return data(column++); }
|
||||
auto integer() -> int64_t { return integer(_output++); }
|
||||
auto decimal() -> uint64_t { return decimal(_output++); }
|
||||
auto real() -> double { return real(_output++); }
|
||||
auto text() -> string { return text(_output++); }
|
||||
auto data() -> vector<uint8_t> { return data(_output++); }
|
||||
|
||||
protected:
|
||||
auto step() -> bool { stepped = true; response = sqlite3_step(stmt); return response == SQLITE_ROW; }
|
||||
auto handle() -> sqlite3_stmt* { if(!stepped) step(); return stmt; }
|
||||
auto finished() -> bool { handle(); return response != SQLITE_ROW; }
|
||||
auto finalize() -> void { handle(); sqlite3_finalize(stmt); stmt = nullptr; }
|
||||
virtual auto statement() -> sqlite3_stmt* { return _statement; }
|
||||
|
||||
private:
|
||||
sqlite3_stmt* stmt = nullptr;
|
||||
bool stepped = false;
|
||||
int response = SQLITE_OK;
|
||||
unsigned column = 0; //this value is not copied/moved via operator=
|
||||
sqlite3_stmt* _statement = nullptr;
|
||||
signed _response = SQLITE_OK;
|
||||
unsigned _output = 0;
|
||||
};
|
||||
|
||||
struct Query : Statement {
|
||||
Query(sqlite3_stmt* stmt) : Statement(stmt) {}
|
||||
Query(const Query& source) : Statement(source) {}
|
||||
Query(Query&& source) : Statement(move(source)) {}
|
||||
~Query() { finalize(); }
|
||||
Query(const Query& source) = delete;
|
||||
auto operator=(const Query& source) -> Query& = delete;
|
||||
|
||||
auto operator=(const Query& source) -> Query& { return Statement::operator=(source), *this; }
|
||||
auto operator=(Query&& source) -> Query& { return Statement::operator=(move(source)), *this; }
|
||||
explicit operator bool() { return !finished(); }
|
||||
Query(sqlite3_stmt* statement) : Statement(statement) {}
|
||||
Query(Query&& source) : Statement(source._statement) { operator=(move(source)); }
|
||||
|
||||
using Statement::step;
|
||||
using Statement::finalize;
|
||||
~Query() {
|
||||
sqlite3_finalize(statement());
|
||||
_statement = nullptr;
|
||||
}
|
||||
|
||||
auto operator=(Query&& source) -> Query& {
|
||||
_statement = source._statement;
|
||||
_input = source._input;
|
||||
source._statement = nullptr;
|
||||
source._input = 0;
|
||||
return *this;
|
||||
}
|
||||
|
||||
auto& bind(unsigned column, nullptr_t) { sqlite3_bind_null(_statement, 1 + column); return *this; }
|
||||
auto& bind(unsigned column, int32_t value) { sqlite3_bind_int(_statement, 1 + column, value); return *this; }
|
||||
auto& bind(unsigned column, uint32_t value) { sqlite3_bind_int(_statement, 1 + column, value); return *this; }
|
||||
auto& bind(unsigned column, int64_t value) { sqlite3_bind_int64(_statement, 1 + column, value); return *this; }
|
||||
auto& bind(unsigned column, uint64_t value) { sqlite3_bind_int64(_statement, 1 + column, value); return *this; }
|
||||
auto& bind(unsigned column, double value) { sqlite3_bind_double(_statement, 1 + column, value); return *this; }
|
||||
auto& bind(unsigned column, const string& value) { sqlite3_bind_text(_statement, 1 + column, value.data(), value.size(), SQLITE_TRANSIENT); return *this; }
|
||||
auto& bind(unsigned column, const vector<uint8_t>& value) { sqlite3_bind_blob(_statement, 1 + column, value.data(), value.size(), SQLITE_TRANSIENT); return *this; }
|
||||
|
||||
auto& bind(nullptr_t) { return bind(_input++, nullptr); }
|
||||
auto& bind(int32_t value) { return bind(_input++, value); }
|
||||
auto& bind(uint32_t value) { return bind(_input++, value); }
|
||||
auto& bind(int64_t value) { return bind(_input++, value); }
|
||||
auto& bind(uint64_t value) { return bind(_input++, value); }
|
||||
auto& bind(double value) { return bind(_input++, value); }
|
||||
auto& bind(const string& value) { return bind(_input++, value); }
|
||||
auto& bind(const vector<uint8_t>& value) { return bind(_input++, value); }
|
||||
|
||||
auto step() -> bool {
|
||||
_stepped = true;
|
||||
return sqlite3_step(_statement) == SQLITE_ROW;
|
||||
}
|
||||
|
||||
struct Iterator {
|
||||
auto operator*() -> Statement { return Statement(query); }
|
||||
Iterator(Query& query, bool finished) : query(query), finished(finished) {}
|
||||
auto operator*() -> Statement { return query._statement; }
|
||||
auto operator!=(const Iterator& source) const -> bool { return finished != source.finished; }
|
||||
auto operator++() -> Iterator& { finished = !query.step(); return *this; }
|
||||
Iterator(Query& query, bool finished) : query(query), finished(finished) {}
|
||||
|
||||
protected:
|
||||
Query& query;
|
||||
bool finished = false;
|
||||
};
|
||||
|
||||
auto begin() -> Iterator { return Iterator(*this, finished()); }
|
||||
auto begin() -> Iterator { return Iterator(*this, !step()); }
|
||||
auto end() -> Iterator { return Iterator(*this, true); }
|
||||
|
||||
private:
|
||||
auto statement() -> sqlite3_stmt* override {
|
||||
if(!_stepped) step();
|
||||
return _statement;
|
||||
}
|
||||
|
||||
unsigned _input = 0;
|
||||
bool _stepped = false;
|
||||
};
|
||||
|
||||
SQLite3() = default;
|
||||
SQLite3(const string& filename) { open(filename); }
|
||||
~SQLite3() { close(); }
|
||||
|
||||
explicit operator bool() const { return database; }
|
||||
explicit operator bool() const { return _database; }
|
||||
|
||||
auto open(const string& filename) -> bool {
|
||||
close();
|
||||
sqlite3_open(filename, &database);
|
||||
return database;
|
||||
sqlite3_open(filename, &_database);
|
||||
return _database;
|
||||
}
|
||||
|
||||
auto close() -> void {
|
||||
sqlite3_close(database);
|
||||
database = nullptr;
|
||||
sqlite3_close(_database);
|
||||
_database = nullptr;
|
||||
}
|
||||
|
||||
template<typename... P> auto execute(const string& statement, P&&... p) -> Query {
|
||||
if(!database) return {nullptr};
|
||||
if(!_database) return {nullptr};
|
||||
|
||||
sqlite3_stmt* stmt = nullptr;
|
||||
sqlite3_prepare_v2(database, statement.data(), statement.size(), &stmt, nullptr);
|
||||
if(!stmt) {
|
||||
if(debug) print("[sqlite3_prepare_v2] ", sqlite3_errmsg(database), "\n");
|
||||
sqlite3_stmt* _statement = nullptr;
|
||||
sqlite3_prepare_v2(_database, statement.data(), statement.size(), &_statement, nullptr);
|
||||
if(!_statement) {
|
||||
if(_debug) print("[sqlite3_prepare_v2] ", sqlite3_errmsg(_database), "\n");
|
||||
return {nullptr};
|
||||
}
|
||||
|
||||
Query query{stmt};
|
||||
_bind(query, 0, forward<P>(p)...);
|
||||
Query query{_statement};
|
||||
bind(query, forward<P>(p)...);
|
||||
return query;
|
||||
}
|
||||
|
||||
auto lastInsertID() const -> uint64_t {
|
||||
return database ? sqlite3_last_insert_rowid(database) : 0;
|
||||
return _database ? sqlite3_last_insert_rowid(_database) : 0;
|
||||
}
|
||||
|
||||
auto setDebug(bool debug = true) -> void {
|
||||
this->debug = debug;
|
||||
_debug = debug;
|
||||
}
|
||||
|
||||
protected:
|
||||
auto _bind(Query&, unsigned) -> void {}
|
||||
template<typename T, typename... P> auto _bind(Query& query, unsigned column, const T& value, P&&... p) -> void {
|
||||
query.bind(column, value);
|
||||
_bind(query, column + 1, forward<P>(p)...);
|
||||
auto bind(Query&) -> void {}
|
||||
template<typename T, typename... P> auto bind(Query& query, const T& value, P&&... p) -> void {
|
||||
query.bind(value);
|
||||
bind(query, forward<P>(p)...);
|
||||
}
|
||||
|
||||
bool debug = false;
|
||||
sqlite3* database = nullptr;
|
||||
bool _debug = false;
|
||||
sqlite3* _database = nullptr;
|
||||
};
|
||||
|
||||
}}
|
||||
|
|
|
@ -19,23 +19,23 @@
|
|||
namespace nall {
|
||||
|
||||
struct directory : storage {
|
||||
static bool create(const string& pathname, unsigned permissions = 0755); //recursive
|
||||
static bool remove(const string& pathname); //recursive
|
||||
static bool exists(const string& pathname);
|
||||
static auto create(const string& pathname, unsigned permissions = 0755) -> bool; //recursive
|
||||
static auto remove(const string& pathname) -> bool; //recursive
|
||||
static auto exists(const string& pathname) -> bool;
|
||||
|
||||
static lstring folders(const string& pathname, const string& pattern = "*") {
|
||||
static auto folders(const string& pathname, const string& pattern = "*") -> lstring {
|
||||
lstring folders = directory::ufolders(pathname, pattern);
|
||||
folders.sort();
|
||||
return folders;
|
||||
}
|
||||
|
||||
static lstring files(const string& pathname, const string& pattern = "*") {
|
||||
static auto files(const string& pathname, const string& pattern = "*") -> lstring {
|
||||
lstring files = directory::ufiles(pathname, pattern);
|
||||
files.sort();
|
||||
return files;
|
||||
}
|
||||
|
||||
static lstring contents(const string& pathname, const string& pattern = "*") {
|
||||
static auto contents(const string& pathname, const string& pattern = "*") -> lstring {
|
||||
lstring folders = directory::ufolders(pathname); //pattern search of contents should only filter files
|
||||
lstring files = directory::ufiles(pathname, pattern);
|
||||
folders.sort();
|
||||
|
@ -44,19 +44,19 @@ struct directory : storage {
|
|||
return folders;
|
||||
}
|
||||
|
||||
static lstring ifolders(const string& pathname, const string& pattern = "*") {
|
||||
static auto ifolders(const string& pathname, const string& pattern = "*") -> lstring {
|
||||
lstring folders = ufolders(pathname, pattern);
|
||||
folders.isort();
|
||||
return folders;
|
||||
}
|
||||
|
||||
static lstring ifiles(const string& pathname, const string& pattern = "*") {
|
||||
static auto ifiles(const string& pathname, const string& pattern = "*") -> lstring {
|
||||
lstring files = ufiles(pathname, pattern);
|
||||
files.isort();
|
||||
return files;
|
||||
}
|
||||
|
||||
static lstring icontents(const string& pathname, const string& pattern = "*") {
|
||||
static auto icontents(const string& pathname, const string& pattern = "*") -> lstring {
|
||||
lstring folders = directory::ufolders(pathname); //pattern search of contents should only filter files
|
||||
lstring files = directory::ufiles(pathname, pattern);
|
||||
folders.isort();
|
||||
|
@ -67,12 +67,12 @@ struct directory : storage {
|
|||
|
||||
private:
|
||||
//internal functions; these return unsorted lists
|
||||
static lstring ufolders(const string& pathname, const string& pattern = "*");
|
||||
static lstring ufiles(const string& pathname, const string& pattern = "*");
|
||||
static auto ufolders(const string& pathname, const string& pattern = "*") -> lstring;
|
||||
static auto ufiles(const string& pathname, const string& pattern = "*") -> lstring;
|
||||
};
|
||||
|
||||
#if defined(PLATFORM_WINDOWS)
|
||||
inline bool directory::create(const string& pathname, unsigned permissions) {
|
||||
inline auto directory::create(const string& pathname, unsigned permissions) -> bool {
|
||||
string path;
|
||||
lstring list = string{pathname}.transform("\\", "/").rtrim("/").split("/");
|
||||
bool result = true;
|
||||
|
@ -83,7 +83,7 @@ private:
|
|||
return result;
|
||||
}
|
||||
|
||||
inline bool directory::remove(const string& pathname) {
|
||||
inline auto directory::remove(const string& pathname) -> bool {
|
||||
lstring list = directory::contents(pathname);
|
||||
for(auto& name : list) {
|
||||
if(name.endsWith("/")) directory::remove({pathname, name});
|
||||
|
@ -92,7 +92,7 @@ private:
|
|||
return _wrmdir(utf16_t(pathname)) == 0;
|
||||
}
|
||||
|
||||
inline bool directory::exists(const string& pathname) {
|
||||
inline auto directory::exists(const string& pathname) -> bool {
|
||||
string name = pathname;
|
||||
name.trim("\"", "\"");
|
||||
DWORD result = GetFileAttributes(utf16_t(name));
|
||||
|
@ -100,7 +100,7 @@ private:
|
|||
return (result & FILE_ATTRIBUTE_DIRECTORY);
|
||||
}
|
||||
|
||||
inline lstring directory::ufolders(const string& pathname, const string& pattern) {
|
||||
inline auto directory::ufolders(const string& pathname, const string& pattern) -> lstring {
|
||||
lstring list;
|
||||
string path = pathname;
|
||||
path.transform("/", "\\");
|
||||
|
@ -130,7 +130,7 @@ private:
|
|||
return list;
|
||||
}
|
||||
|
||||
inline lstring directory::ufiles(const string& pathname, const string& pattern) {
|
||||
inline auto directory::ufiles(const string& pathname, const string& pattern) -> lstring {
|
||||
lstring list;
|
||||
string path = pathname;
|
||||
path.transform("/", "\\");
|
||||
|
@ -155,7 +155,7 @@ private:
|
|||
return list;
|
||||
}
|
||||
#else
|
||||
inline bool directory_is_folder(DIR* dp, struct dirent* ep) {
|
||||
inline auto directory_is_folder(DIR* dp, struct dirent* ep) -> bool {
|
||||
if(ep->d_type == DT_DIR) return true;
|
||||
if(ep->d_type == DT_LNK || ep->d_type == DT_UNKNOWN) {
|
||||
//symbolic links must be resolved to determine type
|
||||
|
@ -166,7 +166,7 @@ private:
|
|||
return false;
|
||||
}
|
||||
|
||||
inline bool directory::create(const string& pathname, unsigned permissions) {
|
||||
inline auto directory::create(const string& pathname, unsigned permissions) -> bool {
|
||||
string path;
|
||||
lstring list = string{pathname}.rtrim("/").split("/");
|
||||
bool result = true;
|
||||
|
@ -178,7 +178,7 @@ private:
|
|||
return result;
|
||||
}
|
||||
|
||||
inline bool directory::remove(const string& pathname) {
|
||||
inline auto directory::remove(const string& pathname) -> bool {
|
||||
lstring list = directory::contents(pathname);
|
||||
for(auto& name : list) {
|
||||
if(name.endsWith("/")) directory::remove({pathname, name});
|
||||
|
@ -187,14 +187,14 @@ private:
|
|||
return rmdir(pathname) == 0;
|
||||
}
|
||||
|
||||
inline bool directory::exists(const string& pathname) {
|
||||
inline auto directory::exists(const string& pathname) -> bool {
|
||||
DIR* dp = opendir(pathname);
|
||||
if(!dp) return false;
|
||||
closedir(dp);
|
||||
return true;
|
||||
}
|
||||
|
||||
inline lstring directory::ufolders(const string& pathname, const string& pattern) {
|
||||
inline auto directory::ufolders(const string& pathname, const string& pattern) -> lstring {
|
||||
lstring list;
|
||||
DIR* dp;
|
||||
struct dirent* ep;
|
||||
|
@ -213,7 +213,7 @@ private:
|
|||
return list;
|
||||
}
|
||||
|
||||
inline lstring directory::ufiles(const string& pathname, const string& pattern) {
|
||||
inline auto directory::ufiles(const string& pathname, const string& pattern) -> lstring {
|
||||
lstring list;
|
||||
DIR* dp;
|
||||
struct dirent* ep;
|
||||
|
|
46
nall/dl.hpp
46
nall/dl.hpp
|
@ -18,25 +18,25 @@
|
|||
namespace nall {
|
||||
|
||||
struct library {
|
||||
explicit operator bool() const { return open(); }
|
||||
bool open() const { return handle; }
|
||||
bool open(const string&, const string& = "");
|
||||
bool open_absolute(const string&);
|
||||
void* sym(const string&);
|
||||
void close();
|
||||
|
||||
library() = default;
|
||||
~library() { close(); }
|
||||
|
||||
library& operator=(const library&) = delete;
|
||||
library(const library&) = delete;
|
||||
|
||||
explicit operator bool() const { return open(); }
|
||||
auto open() const -> bool { return handle; }
|
||||
auto open(const string&, const string& = "") -> bool;
|
||||
auto openAbsolute(const string&) -> bool;
|
||||
auto sym(const string&) -> void*;
|
||||
auto close() -> void;
|
||||
|
||||
private:
|
||||
uintptr_t handle = 0;
|
||||
};
|
||||
|
||||
#if defined(PLATFORM_LINUX) || defined(PLATFORM_BSD)
|
||||
inline bool library::open(const string& name, const string& path) {
|
||||
inline auto library::open(const string& name, const string& path) -> bool {
|
||||
if(handle) close();
|
||||
if(path) handle = (uintptr_t)dlopen(string(path, "lib", name, ".so"), RTLD_LAZY);
|
||||
if(!handle) handle = (uintptr_t)dlopen(string(userpath(), ".local/lib/lib", name, ".so"), RTLD_LAZY);
|
||||
|
@ -45,24 +45,24 @@ inline bool library::open(const string& name, const string& path) {
|
|||
return handle;
|
||||
}
|
||||
|
||||
inline bool library::open_absolute(const string& name) {
|
||||
inline auto library::openAbsolute(const string& name) -> bool {
|
||||
if(handle) close();
|
||||
handle = (uintptr_t)dlopen(name, RTLD_LAZY);
|
||||
return handle;
|
||||
}
|
||||
|
||||
inline void* library::sym(const string& name) {
|
||||
inline auto library::sym(const string& name) -> void* {
|
||||
if(!handle) return nullptr;
|
||||
return dlsym((void*)handle, name);
|
||||
}
|
||||
|
||||
inline void library::close() {
|
||||
inline auto library::close() -> void {
|
||||
if(!handle) return;
|
||||
dlclose((void*)handle);
|
||||
handle = 0;
|
||||
}
|
||||
#elif defined(PLATFORM_MACOSX)
|
||||
inline bool library::open(const string& name, const string& path) {
|
||||
inline auto library::open(const string& name, const string& path) -> bool {
|
||||
if(handle) close();
|
||||
if(path) handle = (uintptr_t)dlopen(string(path, "lib", name, ".dylib"), RTLD_LAZY);
|
||||
if(!handle) handle = (uintptr_t)dlopen(string(userpath(), ".local/lib/lib", name, ".dylib"), RTLD_LAZY);
|
||||
|
@ -71,24 +71,24 @@ inline bool library::open(const string& name, const string& path) {
|
|||
return handle;
|
||||
}
|
||||
|
||||
inline bool library::open_absolute(const string& name) {
|
||||
inline auto library::openAbsolute(const string& name) -> bool {
|
||||
if(handle) close();
|
||||
handle = (uintptr_t)dlopen(name, RTLD_LAZY);
|
||||
return handle;
|
||||
}
|
||||
|
||||
inline void* library::sym(const string& name) {
|
||||
inline auto library::sym(const string& name) -> void* {
|
||||
if(!handle) return nullptr;
|
||||
return dlsym((void*)handle, name);
|
||||
}
|
||||
|
||||
inline void library::close() {
|
||||
inline auto library::close() -> void {
|
||||
if(!handle) return;
|
||||
dlclose((void*)handle);
|
||||
handle = 0;
|
||||
}
|
||||
#elif defined(PLATFORM_WINDOWS)
|
||||
inline bool library::open(const string& name, const string& path) {
|
||||
inline auto library::open(const string& name, const string& path) -> bool {
|
||||
if(handle) close();
|
||||
if(path) {
|
||||
string filepath = {path, name, ".dll"};
|
||||
|
@ -101,27 +101,27 @@ inline bool library::open(const string& name, const string& path) {
|
|||
return handle;
|
||||
}
|
||||
|
||||
inline bool library::open_absolute(const string& name) {
|
||||
inline auto library::openAbsolute(const string& name) -> bool {
|
||||
if(handle) close();
|
||||
handle = (uintptr_t)LoadLibraryW(utf16_t(name));
|
||||
return handle;
|
||||
}
|
||||
|
||||
inline void* library::sym(const string& name) {
|
||||
inline auto library::sym(const string& name) -> void* {
|
||||
if(!handle) return nullptr;
|
||||
return (void*)GetProcAddress((HMODULE)handle, name);
|
||||
}
|
||||
|
||||
inline void library::close() {
|
||||
inline auto library::close() -> void {
|
||||
if(!handle) return;
|
||||
FreeLibrary((HMODULE)handle);
|
||||
handle = 0;
|
||||
}
|
||||
#else
|
||||
inline bool library::open(const string&, const string&) { return false; }
|
||||
inline bool library::open_absolute(const string&) { return false; }
|
||||
inline void* library::sym(const string&) { return nullptr; }
|
||||
inline void library::close() {}
|
||||
inline auto library::open(const string&, const string&) -> bool { return false; }
|
||||
inline auto library::openAbsolute(const string&) -> bool { return false; }
|
||||
inline auto library::sym(const string&) -> void* { return nullptr; }
|
||||
inline auto library::close() -> void {}
|
||||
#endif
|
||||
|
||||
}
|
||||
|
|
|
@ -153,6 +153,13 @@ struct file : storage, varint {
|
|||
return data;
|
||||
}
|
||||
|
||||
auto reads(unsigned length) -> string {
|
||||
string result;
|
||||
result.resize(length);
|
||||
for(auto& byte : result) byte = read();
|
||||
return result;
|
||||
}
|
||||
|
||||
auto read(uint8_t* buffer, unsigned length) -> void {
|
||||
while(length--) *buffer++ = read();
|
||||
}
|
||||
|
@ -179,6 +186,10 @@ struct file : storage, varint {
|
|||
}
|
||||
}
|
||||
|
||||
auto writes(const string& s) -> void {
|
||||
for(auto byte : s) write(byte);
|
||||
}
|
||||
|
||||
auto write(const uint8_t* buffer, unsigned length) -> void {
|
||||
while(length--) write(*buffer++);
|
||||
}
|
||||
|
|
|
@ -22,33 +22,35 @@ namespace nall {
|
|||
struct filemap {
|
||||
enum class mode : unsigned { read, write, readwrite, writeread };
|
||||
|
||||
explicit operator bool() const { return open(); }
|
||||
bool open() const { return p_open(); }
|
||||
bool open(const string& filename, mode mode_) { return p_open(filename, mode_); }
|
||||
void close() { return p_close(); }
|
||||
unsigned size() const { return p_size; }
|
||||
uint8_t* data() { return p_handle; }
|
||||
const uint8_t* data() const { return p_handle; }
|
||||
filemap() { p_ctor(); }
|
||||
filemap(const string& filename, mode mode_) { p_ctor(); p_open(filename, mode_); }
|
||||
~filemap() { p_dtor(); }
|
||||
|
||||
explicit operator bool() const { return open(); }
|
||||
auto open() const -> bool { return p_open(); }
|
||||
auto open(const string& filename, mode mode_) -> bool { return p_open(filename, mode_); }
|
||||
auto close() -> void { return p_close(); }
|
||||
auto size() const -> unsigned { return p_size; }
|
||||
auto data() -> uint8_t* { return p_handle; }
|
||||
auto data() const -> const uint8_t* { return p_handle; }
|
||||
|
||||
private:
|
||||
uint8_t *p_handle = nullptr;
|
||||
uint8_t* p_handle = nullptr;
|
||||
unsigned p_size = 0;
|
||||
|
||||
#if defined(_WIN32)
|
||||
#if defined(API_WINDOWS)
|
||||
//=============
|
||||
//MapViewOfFile
|
||||
//=============
|
||||
|
||||
HANDLE p_filehandle, p_maphandle;
|
||||
HANDLE p_filehandle;
|
||||
HANDLE p_maphandle;
|
||||
|
||||
bool p_open() const {
|
||||
auto p_open() const -> bool {
|
||||
return p_handle;
|
||||
}
|
||||
|
||||
bool p_open(const string& filename, mode mode_) {
|
||||
auto p_open(const string& filename, mode mode_) -> bool {
|
||||
if(file::exists(filename) && file::size(filename) == 0) {
|
||||
p_handle = nullptr;
|
||||
p_size = 0;
|
||||
|
@ -103,7 +105,7 @@ private:
|
|||
return p_handle;
|
||||
}
|
||||
|
||||
void p_close() {
|
||||
auto p_close() -> void {
|
||||
if(p_handle) {
|
||||
UnmapViewOfFile(p_handle);
|
||||
p_handle = nullptr;
|
||||
|
@ -120,12 +122,12 @@ private:
|
|||
}
|
||||
}
|
||||
|
||||
void p_ctor() {
|
||||
auto p_ctor() -> void {
|
||||
p_filehandle = INVALID_HANDLE_VALUE;
|
||||
p_maphandle = INVALID_HANDLE_VALUE;
|
||||
}
|
||||
|
||||
void p_dtor() {
|
||||
auto p_dtor() -> void {
|
||||
close();
|
||||
}
|
||||
|
||||
|
@ -136,11 +138,11 @@ private:
|
|||
|
||||
int p_fd;
|
||||
|
||||
bool p_open() const {
|
||||
auto p_open() const -> bool {
|
||||
return p_handle;
|
||||
}
|
||||
|
||||
bool p_open(const string& filename, mode mode_) {
|
||||
auto p_open(const string& filename, mode mode_) -> bool {
|
||||
if(file::exists(filename) && file::size(filename) == 0) {
|
||||
p_handle = nullptr;
|
||||
p_size = 0;
|
||||
|
@ -187,7 +189,7 @@ private:
|
|||
return p_handle;
|
||||
}
|
||||
|
||||
void p_close() {
|
||||
auto p_close() -> void {
|
||||
if(p_handle) {
|
||||
munmap(p_handle, p_size);
|
||||
p_handle = nullptr;
|
||||
|
@ -199,11 +201,11 @@ private:
|
|||
}
|
||||
}
|
||||
|
||||
void p_ctor() {
|
||||
auto p_ctor() -> void {
|
||||
p_fd = -1;
|
||||
}
|
||||
|
||||
void p_dtor() {
|
||||
auto p_dtor() -> void {
|
||||
p_close();
|
||||
}
|
||||
|
||||
|
|
|
@ -5,52 +5,30 @@
|
|||
|
||||
namespace nall {
|
||||
|
||||
template<typename T> class function;
|
||||
template<typename T> struct function;
|
||||
|
||||
template<typename R, typename... P> class function<R (P...)> {
|
||||
struct container {
|
||||
virtual R operator()(P... p) const = 0;
|
||||
virtual container* copy() const = 0;
|
||||
virtual ~container() {}
|
||||
};
|
||||
|
||||
container* callback = nullptr;
|
||||
|
||||
struct global : container {
|
||||
R (*function)(P...);
|
||||
R operator()(P... p) const { return function(forward<P>(p)...); }
|
||||
container* copy() const { return new global(function); }
|
||||
global(R (*function)(P...)) : function(function) {}
|
||||
};
|
||||
|
||||
template<typename C> struct member : container {
|
||||
R (C::*function)(P...);
|
||||
C* object;
|
||||
R operator()(P... p) const { return (object->*function)(forward<P>(p)...); }
|
||||
container* copy() const { return new member(function, object); }
|
||||
member(R (C::*function)(P...), C* object) : function(function), object(object) {}
|
||||
};
|
||||
|
||||
template<typename L> struct lambda : container {
|
||||
mutable L object;
|
||||
R operator()(P... p) const { return object(forward<P>(p)...); }
|
||||
container* copy() const { return new lambda(object); }
|
||||
lambda(const L& object) : object(object) {}
|
||||
};
|
||||
|
||||
//value = true if R L::operator()(P...) exists
|
||||
template<typename R, typename... P> struct function<R (P...)> {
|
||||
//value = true if auto L::operator()(P...) -> R exists
|
||||
template<typename L> struct is_compatible {
|
||||
template<typename T> static const typename is_same<R, decltype(declval<T>().operator()(declval<P>()...))>::type exists(T*);
|
||||
template<typename T> static const false_type exists(...);
|
||||
template<typename T> static auto exists(T*) -> const typename is_same<R, decltype(declval<T>().operator()(declval<P>()...))>::type;
|
||||
template<typename T> static auto exists(...) -> const false_type;
|
||||
static constexpr bool value = decltype(exists<L>(0))::value;
|
||||
};
|
||||
|
||||
public:
|
||||
explicit operator bool() const { return callback; }
|
||||
R operator()(P... p) const { return (*callback)(forward<P>(p)...); }
|
||||
void reset() { if(callback) { delete callback; callback = nullptr; } }
|
||||
function() = default;
|
||||
function(const function& source) { operator=(source); }
|
||||
function(void* function) { if(function) callback = new global((auto (*)(P...) -> R)function); }
|
||||
function(auto (*function)(P...) -> R) { callback = new global(function); }
|
||||
template<typename C> function(auto (C::*function)(P...) -> R, C* object) { callback = new member<C>(function, object); }
|
||||
template<typename C> function(auto (C::*function)(P...) const -> R, C* object) { callback = new member<C>((auto (C::*)(P...) -> R)function, object); }
|
||||
template<typename L, typename = enable_if<is_compatible<L>>> function(const L& object) { callback = new lambda<L>(object); }
|
||||
~function() { if(callback) delete callback; }
|
||||
|
||||
function& operator=(const function& source) {
|
||||
explicit operator bool() const { return callback; }
|
||||
auto operator()(P... p) const -> R { return (*callback)(forward<P>(p)...); }
|
||||
auto reset() -> void { if(callback) { delete callback; callback = nullptr; } }
|
||||
|
||||
auto operator=(const function& source) -> function& {
|
||||
if(this != &source) {
|
||||
if(callback) { delete callback; callback = nullptr; }
|
||||
if(source.callback) callback = source.callback->copy();
|
||||
|
@ -58,14 +36,36 @@ public:
|
|||
return *this;
|
||||
}
|
||||
|
||||
function() = default;
|
||||
function(const function& source) { operator=(source); }
|
||||
function(void* function) { if(function) callback = new global((R (*)(P...))function); }
|
||||
function(R (*function)(P...)) { callback = new global(function); }
|
||||
template<typename C> function(R (C::*function)(P...), C* object) { callback = new member<C>(function, object); }
|
||||
template<typename C> function(R (C::*function)(P...) const, C* object) { callback = new member<C>((R (C::*)(P...))function, object); }
|
||||
template<typename L, typename = enable_if<is_compatible<L>>> function(const L& object) { callback = new lambda<L>(object); }
|
||||
~function() { if(callback) delete callback; }
|
||||
private:
|
||||
struct container {
|
||||
virtual auto operator()(P... p) const -> R = 0;
|
||||
virtual auto copy() const -> container* = 0;
|
||||
virtual ~container() = default;
|
||||
};
|
||||
|
||||
container* callback = nullptr;
|
||||
|
||||
struct global : container {
|
||||
auto (*function)(P...) -> R;
|
||||
auto operator()(P... p) const -> R { return function(forward<P>(p)...); }
|
||||
auto copy() const -> container* { return new global(function); }
|
||||
global(auto (*function)(P...) -> R) : function(function) {}
|
||||
};
|
||||
|
||||
template<typename C> struct member : container {
|
||||
auto (C::*function)(P...) -> R;
|
||||
C* object;
|
||||
auto operator()(P... p) const -> R { return (object->*function)(forward<P>(p)...); }
|
||||
auto copy() const -> container* { return new member(function, object); }
|
||||
member(auto (C::*function)(P...) -> R, C* object) : function(function), object(object) {}
|
||||
};
|
||||
|
||||
template<typename L> struct lambda : container {
|
||||
mutable L object;
|
||||
auto operator()(P... p) const -> R { return object(forward<P>(p)...); }
|
||||
auto copy() const -> container* { return new lambda(object); }
|
||||
lambda(const L& object) : object(object) {}
|
||||
};
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -1,66 +0,0 @@
|
|||
#ifndef NALL_GROUP_HPP
|
||||
#define NALL_GROUP_HPP
|
||||
|
||||
//group
|
||||
//vector of unique references
|
||||
|
||||
#include <nall/vector.hpp>
|
||||
|
||||
namespace nall {
|
||||
|
||||
template<typename T> struct group : protected vector<T*> {
|
||||
group& operator=(const group& source) { vector<T*>::operator=(source); return *this; }
|
||||
group& operator=(group&& source) { vector<T*>::operator=(std::move(source)); return *this; }
|
||||
template<typename... Args> group(Args&&... args) { construct(std::forward<Args>(args)...); }
|
||||
|
||||
bool empty() const { return vector<T*>::empty(); }
|
||||
unsigned size() const { return vector<T*>::size(); }
|
||||
void reset() { vector<T*>::reset(); }
|
||||
|
||||
T& first() const { return *vector<T*>::operator[](0); }
|
||||
|
||||
//return true if at least one item was appended
|
||||
template<typename... Args> bool append(T& value, Args&&... args) {
|
||||
bool result = append(value);
|
||||
return append(std::forward<Args>(args)...) | result;
|
||||
}
|
||||
|
||||
bool append(T& value) {
|
||||
if(vector<T*>::find(&value)) return false;
|
||||
return vector<T*>::append(&value), true;
|
||||
}
|
||||
|
||||
//return true if at least one item was removed
|
||||
template<typename... Args> bool remove(T& value, Args&&... args) {
|
||||
bool result = remove(value);
|
||||
return remove(std::forward<Args>(args)...) | result;
|
||||
}
|
||||
|
||||
bool remove(T& value) {
|
||||
if(auto position = vector<T*>::find(&value)) return vector<T*>::remove(position()), true;
|
||||
return false;
|
||||
}
|
||||
|
||||
struct iterator : protected vector<T*>::constIterator {
|
||||
T& operator*() const { return *vector<T*>::constIterator::operator*(); }
|
||||
bool operator!=(const iterator& source) const { return vector<T*>::constIterator::operator!=(source); }
|
||||
iterator& operator++() { vector<T*>::constIterator::operator++(); return *this; }
|
||||
iterator(const group& source, unsigned position) : vector<T*>::constIterator(source, position) {}
|
||||
};
|
||||
|
||||
const iterator begin() const { return iterator(*this, 0); }
|
||||
const iterator end() const { return iterator(*this, size()); }
|
||||
|
||||
private:
|
||||
void construct() {}
|
||||
void construct(const group& source) { vector<T*>::operator=(source); }
|
||||
void construct(group&& source) { vector<T*>::operator=(std::move(source)); }
|
||||
template<typename... Args> void construct(T& value, Args&&... args) {
|
||||
append(value);
|
||||
construct(std::forward<Args>(args)...);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
|
@ -8,26 +8,20 @@
|
|||
//remove: O(1) average; O(n) worst
|
||||
//
|
||||
//requirements:
|
||||
// unsigned T::hash() const;
|
||||
// bool T::operator==(const T&) const;
|
||||
// auto T::hash() const -> unsigned;
|
||||
// auto T::operator==(const T&) const -> bool;
|
||||
|
||||
namespace nall {
|
||||
|
||||
template<typename T>
|
||||
struct hashset {
|
||||
protected:
|
||||
T** pool = nullptr;
|
||||
unsigned length = 8; //length of pool
|
||||
unsigned count = 0; //number of objects inside of the pool
|
||||
|
||||
public:
|
||||
hashset() {}
|
||||
hashset() = default;
|
||||
hashset(unsigned length) : length(bit::round(length)) {}
|
||||
hashset(const hashset& source) { operator=(source); }
|
||||
hashset(hashset&& source) { operator=(std::move(source)); }
|
||||
hashset(hashset&& source) { operator=(move(source)); }
|
||||
~hashset() { reset(); }
|
||||
|
||||
hashset& operator=(const hashset& source) {
|
||||
auto operator=(const hashset& source) -> hashset& {
|
||||
reset();
|
||||
if(source.pool) {
|
||||
for(unsigned n = 0; n < source.count; n++) {
|
||||
|
@ -37,7 +31,7 @@ public:
|
|||
return *this;
|
||||
}
|
||||
|
||||
hashset& operator=(hashset&& source) {
|
||||
auto operator=(hashset&& source) -> hashset& {
|
||||
reset();
|
||||
pool = source.pool;
|
||||
length = source.length;
|
||||
|
@ -48,11 +42,11 @@ public:
|
|||
return *this;
|
||||
}
|
||||
|
||||
unsigned capacity() const { return length; }
|
||||
unsigned size() const { return count; }
|
||||
bool empty() const { return count == 0; }
|
||||
auto capacity() const -> unsigned { return length; }
|
||||
auto size() const -> unsigned { return count; }
|
||||
auto empty() const -> bool { return count == 0; }
|
||||
|
||||
void reset() {
|
||||
auto reset() -> void {
|
||||
if(pool) {
|
||||
for(unsigned n = 0; n < length; n++) {
|
||||
if(pool[n]) {
|
||||
|
@ -67,7 +61,7 @@ public:
|
|||
count = 0;
|
||||
}
|
||||
|
||||
void reserve(unsigned size) {
|
||||
auto reserve(unsigned size) -> void {
|
||||
//ensure all items will fit into pool (with <= 50% load) and amortize growth
|
||||
size = bit::round(max(size, count << 1));
|
||||
T** copy = new T*[size]();
|
||||
|
@ -88,7 +82,7 @@ public:
|
|||
length = size;
|
||||
}
|
||||
|
||||
maybe<T&> find(const T& value) {
|
||||
auto find(const T& value) -> maybe<T&> {
|
||||
if(!pool) return nothing;
|
||||
|
||||
unsigned hash = value.hash() & (length - 1);
|
||||
|
@ -100,7 +94,7 @@ public:
|
|||
return nothing;
|
||||
}
|
||||
|
||||
maybe<T&> insert(const T& value) {
|
||||
auto insert(const T& value) -> maybe<T&> {
|
||||
if(!pool) pool = new T*[length]();
|
||||
|
||||
//double pool size when load is >= 50%
|
||||
|
@ -114,7 +108,7 @@ public:
|
|||
return *pool[hash];
|
||||
}
|
||||
|
||||
bool remove(const T& value) {
|
||||
auto remove(const T& value) -> bool {
|
||||
if(!pool) return false;
|
||||
|
||||
unsigned hash = value.hash() & (length - 1);
|
||||
|
@ -130,6 +124,11 @@ public:
|
|||
|
||||
return false;
|
||||
}
|
||||
|
||||
protected:
|
||||
T** pool = nullptr;
|
||||
unsigned length = 8; //length of pool
|
||||
unsigned count = 0; //number of objects inside of the pool
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -18,9 +18,9 @@ struct httpRequest : httpMessage {
|
|||
inline auto body(const function<bool (const uint8_t* data, unsigned size)>& callback) const -> bool;
|
||||
inline auto setBody() -> bool;
|
||||
|
||||
auto ip() const -> string {
|
||||
return {(uint8_t)(_ip >> 24), ".", (uint8_t)(_ip >> 16), ".", (uint8_t)(_ip >> 8), ".", (uint8_t)(_ip >> 0)};
|
||||
}
|
||||
auto ipv4() const -> bool { return _ipv6 == false; }
|
||||
auto ipv6() const -> bool { return _ipv6 == true; }
|
||||
auto ip() const -> string { return _ip; }
|
||||
|
||||
auto requestType() const -> RequestType { return _requestType; }
|
||||
auto setRequestType(RequestType value) -> void { _requestType = value; }
|
||||
|
@ -42,7 +42,8 @@ struct httpRequest : httpMessage {
|
|||
auto setPost(const string& name, const string& value = "") -> void { _post.set(name, value); }
|
||||
|
||||
//private:
|
||||
uint32_t _ip = 0;
|
||||
bool _ipv6 = false;
|
||||
string _ip;
|
||||
RequestType _requestType = RequestType::None;
|
||||
string _path;
|
||||
httpVariables _cookie;
|
||||
|
@ -60,7 +61,7 @@ auto httpRequest::head(const function<bool (const uint8_t*, unsigned)>& callback
|
|||
for(auto& get : _get) {
|
||||
request.append(get.name, "=", get.value, "&");
|
||||
}
|
||||
request.rtrim("&");
|
||||
request.rtrim("&", 1L);
|
||||
}
|
||||
|
||||
switch(requestType()) {
|
||||
|
@ -83,43 +84,43 @@ auto httpRequest::setHead() -> bool {
|
|||
string request = headers.takeFirst().rtrim("\r");
|
||||
string requestHost;
|
||||
|
||||
if(irtrim(request, " HTTP/1.0"));
|
||||
else if(irtrim(request, " HTTP/1.1"));
|
||||
if(request.iendsWith(" HTTP/1.0")) request.irtrim(" HTTP/1.0", 1L);
|
||||
else if(request.iendsWith(" HTTP/1.1")) request.irtrim(" HTTP/1.1", 1L);
|
||||
else return false;
|
||||
|
||||
if(iltrim(request, "HEAD ")) setRequestType(RequestType::Head);
|
||||
else if(iltrim(request, "GET " )) setRequestType(RequestType::Get );
|
||||
else if(iltrim(request, "POST ")) setRequestType(RequestType::Post);
|
||||
if(request.ibeginsWith("HEAD ")) request.iltrim("HEAD ", 1L), setRequestType(RequestType::Head);
|
||||
else if(request.ibeginsWith("GET " )) request.iltrim("GET ", 1L), setRequestType(RequestType::Get );
|
||||
else if(request.ibeginsWith("POST ")) request.iltrim("POST ", 1L), setRequestType(RequestType::Post);
|
||||
else return false;
|
||||
|
||||
//decode absolute URIs
|
||||
request.strip().iltrim("http://");
|
||||
request.strip().iltrim("http://", 1L);
|
||||
if(!request.beginsWith("/")) {
|
||||
lstring components = request.split<1>("/");
|
||||
lstring components = request.split("/", 1L);
|
||||
requestHost = components(0);
|
||||
request = {"/", components(1)};
|
||||
}
|
||||
|
||||
lstring components = request.split<1>("?");
|
||||
lstring components = request.split("?", 1L);
|
||||
setPath(components(0));
|
||||
|
||||
if(auto queryString = components(1)) {
|
||||
for(auto& block : queryString.split("&")) {
|
||||
lstring variable = block.split<1>("=");
|
||||
lstring variable = block.split("=", 1L);
|
||||
if(variable(0)) setGet(variable(0), variable(1));
|
||||
}
|
||||
}
|
||||
|
||||
for(auto& header : headers) {
|
||||
if(header.beginsWith(" ") || header.beginsWith("\t")) continue;
|
||||
auto part = header.split<1>(":").strip();
|
||||
auto part = header.split(":", 1L).strip();
|
||||
if(!part[0] || part.size() != 2) continue;
|
||||
appendHeader(part[0], part[1]);
|
||||
|
||||
if(part[0].iequals("Cookie")) {
|
||||
for(auto& block : part[1].split(";")) {
|
||||
lstring variable = block.split<1>("=").strip();
|
||||
variable(1).ltrim("\"").rtrim("\"");
|
||||
lstring variable = block.split("=", 1L).strip();
|
||||
variable(1).trim("\"", "\"");
|
||||
if(variable(0)) setCookie(variable(0), variable(1));
|
||||
}
|
||||
}
|
||||
|
@ -143,7 +144,7 @@ auto httpRequest::setBody() -> bool {
|
|||
if(requestType() == RequestType::Post) {
|
||||
if(header("Content-Type").iequals("application/x-www-form-urlencoded")) {
|
||||
for(auto& block : _body.split("&")) {
|
||||
lstring variable = block.rtrim("\r").split<1>("=");
|
||||
lstring variable = block.rtrim("\r").split("=", 1L);
|
||||
if(variable(0)) setPost(variable(0), variable(1));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -95,15 +95,15 @@ auto httpResponse::setHead() -> bool {
|
|||
lstring headers = _head.split("\n");
|
||||
string response = headers.takeFirst().rtrim("\r");
|
||||
|
||||
if(iltrim(response, "HTTP/1.0 "));
|
||||
else if(iltrim(response, "HTTP/1.1 "));
|
||||
if(response.ibeginsWith("HTTP/1.0 ")) response.iltrim("HTTP/1.0 ", 1L);
|
||||
else if(response.ibeginsWith("HTTP/1.1 ")) response.iltrim("HTTP/1.1 ", 1L);
|
||||
else return false;
|
||||
|
||||
setResponseType(decimal(response));
|
||||
|
||||
for(auto& header : headers) {
|
||||
if(header.beginsWith(" ") || header.beginsWith("\t")) continue;
|
||||
lstring variable = header.split<1>(":").strip();
|
||||
lstring variable = header.split(":", 1L).strip();
|
||||
if(variable.size() != 2) continue;
|
||||
appendHeader(variable[0], variable[1]);
|
||||
}
|
||||
|
|
|
@ -14,10 +14,22 @@ struct httpServer : httpRole, service {
|
|||
~httpServer() { close(); }
|
||||
|
||||
private:
|
||||
signed fd = -1;
|
||||
function<httpResponse (httpRequest&)> callback;
|
||||
struct sockaddr_in addrin = {0};
|
||||
std::atomic<signed> connections{0};
|
||||
|
||||
signed fd4 = -1;
|
||||
signed fd6 = -1;
|
||||
struct sockaddr_in addrin4 = {0};
|
||||
struct sockaddr_in6 addrin6 = {0};
|
||||
|
||||
auto ipv4() const -> bool { return fd4 >= 0; }
|
||||
auto ipv6() const -> bool { return fd6 >= 0; }
|
||||
|
||||
auto ipv4_close() -> void { if(fd4 >= 0) ::close(fd4); fd4 = -1; }
|
||||
auto ipv6_close() -> void { if(fd6 >= 0) ::close(fd6); fd6 = -1; }
|
||||
|
||||
auto ipv4_scan() -> bool;
|
||||
auto ipv6_scan() -> bool;
|
||||
};
|
||||
|
||||
auto httpServer::open(unsigned port, const string& serviceName, const string& command) -> bool {
|
||||
|
@ -25,8 +37,9 @@ auto httpServer::open(unsigned port, const string& serviceName, const string& co
|
|||
if(!service::command(serviceName, command)) return false;
|
||||
}
|
||||
|
||||
fd = socket(AF_INET, SOCK_STREAM, 0);
|
||||
if(fd < 0) return false;
|
||||
fd4 = socket(AF_INET, SOCK_STREAM, 0);
|
||||
fd6 = socket(AF_INET6, SOCK_STREAM, 0);
|
||||
if(!ipv4() && !ipv6()) return false;
|
||||
|
||||
{
|
||||
#if defined(SO_RCVTIMEO)
|
||||
|
@ -34,7 +47,8 @@ auto httpServer::open(unsigned port, const string& serviceName, const string& co
|
|||
struct timeval rcvtimeo;
|
||||
rcvtimeo.tv_sec = settings.timeoutReceive / 1000;
|
||||
rcvtimeo.tv_usec = settings.timeoutReceive % 1000 * 1000;
|
||||
setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, &rcvtimeo, sizeof(struct timeval));
|
||||
if(ipv4()) setsockopt(fd4, SOL_SOCKET, SO_RCVTIMEO, &rcvtimeo, sizeof(struct timeval));
|
||||
if(ipv6()) setsockopt(fd6, SOL_SOCKET, SO_RCVTIMEO, &rcvtimeo, sizeof(struct timeval));
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -43,37 +57,41 @@ auto httpServer::open(unsigned port, const string& serviceName, const string& co
|
|||
struct timeval sndtimeo;
|
||||
sndtimeo.tv_sec = settings.timeoutSend / 1000;
|
||||
sndtimeo.tv_usec = settings.timeoutSend % 1000 * 1000;
|
||||
setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, &sndtimeo, sizeof(struct timeval));
|
||||
if(ipv4()) setsockopt(fd4, SOL_SOCKET, SO_SNDTIMEO, &sndtimeo, sizeof(struct timeval));
|
||||
if(ipv6()) setsockopt(fd6, SOL_SOCKET, SO_SNDTIMEO, &sndtimeo, sizeof(struct timeval));
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(SO_NOSIGPIPE) //BSD, OSX
|
||||
signed nosigpipe = 1;
|
||||
setsockopt(fd, SOL_SOCKET, SO_NOSIGPIPE, &nosigpipe, sizeof(signed));
|
||||
if(ipv4()) setsockopt(fd4, SOL_SOCKET, SO_NOSIGPIPE, &nosigpipe, sizeof(signed));
|
||||
if(ipv6()) setsockopt(fd6, SOL_SOCKET, SO_NOSIGPIPE, &nosigpipe, sizeof(signed));
|
||||
#endif
|
||||
|
||||
#if defined(SO_REUSEADDR) //BSD, Linux, OSX
|
||||
signed reuseaddr = 1;
|
||||
setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &reuseaddr, sizeof(signed));
|
||||
if(ipv4()) setsockopt(fd4, SOL_SOCKET, SO_REUSEADDR, &reuseaddr, sizeof(signed));
|
||||
if(ipv6()) setsockopt(fd6, SOL_SOCKET, SO_REUSEADDR, &reuseaddr, sizeof(signed));
|
||||
#endif
|
||||
|
||||
#if defined(SO_REUSEPORT) //BSD, OSX
|
||||
signed reuseport = 1;
|
||||
setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &reuseport, sizeof(signed));
|
||||
if(ipv4()) setsockopt(fd4, SOL_SOCKET, SO_REUSEPORT, &reuseport, sizeof(signed));
|
||||
if(ipv6()) setsockopt(fd6, SOL_SOCKET, SO_REUSEPORT, &reuseport, sizeof(signed));
|
||||
#endif
|
||||
}
|
||||
|
||||
addrin.sin_family = AF_INET;
|
||||
addrin.sin_addr.s_addr = htonl(INADDR_ANY);
|
||||
addrin.sin_port = htons(port);
|
||||
addrin4.sin_family = AF_INET;
|
||||
addrin4.sin_addr.s_addr = htonl(INADDR_ANY);
|
||||
addrin4.sin_port = htons(port);
|
||||
|
||||
signed result = bind(fd, (struct sockaddr*)&addrin, sizeof(addrin));
|
||||
if(result < 0) return close(), false;
|
||||
addrin6.sin6_family = AF_INET6;
|
||||
addrin6.sin6_addr = in6addr_any;
|
||||
addrin6.sin6_port = htons(port);
|
||||
|
||||
result = listen(fd, SOMAXCONN); //system-wide limit (per port)
|
||||
if(result < 0) return close(), false;
|
||||
|
||||
return true;
|
||||
if(bind(fd4, (struct sockaddr*)&addrin4, sizeof(addrin4)) < 0 || listen(fd4, SOMAXCONN) < 0) ipv4_close();
|
||||
if(bind(fd6, (struct sockaddr*)&addrin6, sizeof(addrin6)) < 0 || listen(fd6, SOMAXCONN) < 0) ipv6_close();
|
||||
return ipv4() || ipv6();
|
||||
}
|
||||
|
||||
auto httpServer::main(const function<httpResponse (httpRequest&)>& function) -> void {
|
||||
|
@ -82,15 +100,19 @@ auto httpServer::main(const function<httpResponse (httpRequest&)>& function) ->
|
|||
|
||||
auto httpServer::scan() -> string {
|
||||
if(auto command = service::receive()) return command;
|
||||
|
||||
if(connections >= settings.connectionLimit) return "busy";
|
||||
if(ipv4() && ipv4_scan()) return "ok";
|
||||
if(ipv6() && ipv6_scan()) return "ok";
|
||||
return "idle";
|
||||
}
|
||||
|
||||
auto httpServer::ipv4_scan() -> bool {
|
||||
struct pollfd query = {0};
|
||||
query.fd = fd;
|
||||
query.fd = fd4;
|
||||
query.events = POLLIN;
|
||||
poll(&query, 1, 0);
|
||||
|
||||
if(query.fd == fd && query.revents & POLLIN) {
|
||||
if(query.fd == fd4 && query.revents & POLLIN) {
|
||||
++connections;
|
||||
|
||||
thread::create([&](uintptr_t) {
|
||||
|
@ -100,11 +122,19 @@ auto httpServer::scan() -> string {
|
|||
struct sockaddr_in settings = {0};
|
||||
socklen_t socklen = sizeof(sockaddr_in);
|
||||
|
||||
clientfd = accept(fd, (struct sockaddr*)&settings, &socklen);
|
||||
clientfd = accept(fd4, (struct sockaddr*)&settings, &socklen);
|
||||
if(clientfd < 0) return;
|
||||
|
||||
uint32_t ip = ntohl(settings.sin_addr.s_addr);
|
||||
|
||||
httpRequest request;
|
||||
request._ip = ntohl(settings.sin_addr.s_addr);
|
||||
request._ipv6 = false;
|
||||
request._ip = {
|
||||
(uint8_t)(ip >> 24), ".",
|
||||
(uint8_t)(ip >> 16), ".",
|
||||
(uint8_t)(ip >> 8), ".",
|
||||
(uint8_t)(ip >> 0)
|
||||
};
|
||||
|
||||
if(download(clientfd, request) && callback) {
|
||||
auto response = callback(request);
|
||||
|
@ -116,16 +146,64 @@ auto httpServer::scan() -> string {
|
|||
::close(clientfd);
|
||||
--connections;
|
||||
}, 0, settings.threadStackSize);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return "ok";
|
||||
return false;
|
||||
}
|
||||
|
||||
auto httpServer::ipv6_scan() -> bool {
|
||||
struct pollfd query = {0};
|
||||
query.fd = fd6;
|
||||
query.events = POLLIN;
|
||||
poll(&query, 1, 0);
|
||||
|
||||
if(query.fd == fd6 && query.revents & POLLIN) {
|
||||
++connections;
|
||||
|
||||
thread::create([&](uintptr_t) {
|
||||
thread::detach();
|
||||
|
||||
signed clientfd = -1;
|
||||
struct sockaddr_in6 settings = {0};
|
||||
socklen_t socklen = sizeof(sockaddr_in6);
|
||||
|
||||
clientfd = accept(fd6, (struct sockaddr*)&settings, &socklen);
|
||||
if(clientfd < 0) return;
|
||||
|
||||
unsigned char* ip = settings.sin6_addr.s6_addr;
|
||||
uint16_t ipSegment[8] = {0};
|
||||
for(auto n : range(8)) ipSegment[n] = ip[n * 2 + 0] * 256 + ip[n * 2 + 1];
|
||||
|
||||
httpRequest request;
|
||||
request._ipv6 = true;
|
||||
for(auto n : range(8)) {
|
||||
uint16_t value = ip[n * 2 + 0] * 256 + ip[n * 2 + 1];
|
||||
request._ip.append(hex(value, 4L));
|
||||
if(n != 7) request._ip.append(":");
|
||||
}
|
||||
|
||||
if(download(clientfd, request) && callback) {
|
||||
auto response = callback(request);
|
||||
upload(clientfd, response);
|
||||
} else {
|
||||
upload(clientfd, httpResponse()); //"501 Not Implemented"
|
||||
}
|
||||
|
||||
::close(clientfd);
|
||||
--connections;
|
||||
}, 0, settings.threadStackSize);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
auto httpServer::close() -> void {
|
||||
if(fd) {
|
||||
::close(fd);
|
||||
fd = -1;
|
||||
}
|
||||
ipv4_close();
|
||||
ipv6_close();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -4,27 +4,27 @@
|
|||
namespace nall {
|
||||
|
||||
struct Interpolation {
|
||||
static inline double Nearest(double mu, double a, double b, double c, double d) {
|
||||
static inline auto Nearest(double mu, double a, double b, double c, double d) -> double {
|
||||
return (mu <= 0.5 ? b : c);
|
||||
}
|
||||
|
||||
static inline double Sublinear(double mu, double a, double b, double c, double d) {
|
||||
static inline auto Sublinear(double mu, double a, double b, double c, double d) -> double {
|
||||
mu = ((mu - 0.5) * 2.0) + 0.5;
|
||||
if(mu < 0) mu = 0;
|
||||
if(mu > 1) mu = 1;
|
||||
return b * (1.0 - mu) + c * mu;
|
||||
}
|
||||
|
||||
static inline double Linear(double mu, double a, double b, double c, double d) {
|
||||
static inline auto Linear(double mu, double a, double b, double c, double d) -> double {
|
||||
return b * (1.0 - mu) + c * mu;
|
||||
}
|
||||
|
||||
static inline double Cosine(double mu, double a, double b, double c, double d) {
|
||||
static inline auto Cosine(double mu, double a, double b, double c, double d) -> double {
|
||||
mu = (1.0 - cos(mu * 3.14159265)) / 2.0;
|
||||
return b * (1.0 - mu) + c * mu;
|
||||
}
|
||||
|
||||
static inline double Cubic(double mu, double a, double b, double c, double d) {
|
||||
static inline auto Cubic(double mu, double a, double b, double c, double d) -> double {
|
||||
double A = d - c - a + b;
|
||||
double B = a - b - A;
|
||||
double C = c - a;
|
||||
|
@ -32,7 +32,7 @@ struct Interpolation {
|
|||
return A * (mu * mu * mu) + B * (mu * mu) + C * mu + D;
|
||||
}
|
||||
|
||||
static inline double Hermite(double mu1, double a, double b, double c, double d) {
|
||||
static inline auto Hermite(double mu1, double a, double b, double c, double d) -> double {
|
||||
const double tension = 0.0; //-1 = low, 0 = normal, +1 = high
|
||||
const double bias = 0.0; //-1 = left, 0 = even, +1 = right
|
||||
double mu2, mu3, m0, m1, a0, a1, a2, a3;
|
||||
|
|
46
nall/map.hpp
46
nall/map.hpp
|
@ -9,45 +9,47 @@ template<typename T, typename U> struct map {
|
|||
struct node_t {
|
||||
T key;
|
||||
U value;
|
||||
bool operator< (const node_t& source) const { return key < source.key; }
|
||||
bool operator==(const node_t& source) const { return key == source.key; }
|
||||
node_t() = default;
|
||||
node_t(const T& key) : key(key) {}
|
||||
node_t(const T& key, const U& value) : key(key), value(value) {}
|
||||
auto operator< (const node_t& source) const -> bool { return key < source.key; }
|
||||
auto operator==(const node_t& source) const -> bool { return key == source.key; }
|
||||
};
|
||||
|
||||
maybe<U&> find(const T& key) const {
|
||||
auto find(const T& key) const -> maybe<U&> {
|
||||
if(auto node = root.find({key})) return node().value;
|
||||
return nothing;
|
||||
}
|
||||
|
||||
void insert(const T& key, const U& value) { root.insert({key, value}); }
|
||||
void remove(const T& key) { root.remove({key}); }
|
||||
unsigned size() const { return root.size(); }
|
||||
void reset() { root.reset(); }
|
||||
auto insert(const T& key, const U& value) -> void { root.insert({key, value}); }
|
||||
auto remove(const T& key) -> void { root.remove({key}); }
|
||||
auto size() const -> unsigned { return root.size(); }
|
||||
auto reset() -> void { root.reset(); }
|
||||
|
||||
typename set<node_t>::iterator begin() { return root.begin(); }
|
||||
typename set<node_t>::iterator end() { return root.end(); }
|
||||
const typename set<node_t>::iterator begin() const { return root.begin(); }
|
||||
const typename set<node_t>::iterator end() const { return root.end(); }
|
||||
auto begin() -> typename set<node_t>::iterator { return root.begin(); }
|
||||
auto end() -> typename set<node_t>::iterator { return root.end(); }
|
||||
|
||||
auto begin() const -> const typename set<node_t>::iterator { return root.begin(); }
|
||||
auto end() const -> const typename set<node_t>::iterator { return root.end(); }
|
||||
|
||||
protected:
|
||||
set<node_t> root;
|
||||
};
|
||||
|
||||
template<typename T, typename U> struct bimap {
|
||||
maybe<U&> find(const T& key) const { return tmap.find(key); }
|
||||
maybe<T&> find(const U& key) const { return umap.find(key); }
|
||||
void insert(const T& key, const U& value) { tmap.insert(key, value); umap.insert(value, key); }
|
||||
void remove(const T& key) { if(auto p = tmap.find(key)) { umap.remove(p().value); tmap.remove(key); } }
|
||||
void remove(const U& key) { if(auto p = umap.find(key)) { tmap.remove(p().value); umap.remove(key); } }
|
||||
unsigned size() const { return tmap.size(); }
|
||||
void reset() { tmap.reset(); umap.reset(); }
|
||||
auto find(const T& key) const -> maybe<U&> { return tmap.find(key); }
|
||||
auto find(const U& key) const -> maybe<T&> { return umap.find(key); }
|
||||
auto insert(const T& key, const U& value) -> void { tmap.insert(key, value); umap.insert(value, key); }
|
||||
auto remove(const T& key) -> void { if(auto p = tmap.find(key)) { umap.remove(p().value); tmap.remove(key); } }
|
||||
auto remove(const U& key) -> void { if(auto p = umap.find(key)) { tmap.remove(p().value); umap.remove(key); } }
|
||||
auto size() const -> unsigned { return tmap.size(); }
|
||||
auto reset() -> void { tmap.reset(); umap.reset(); }
|
||||
|
||||
typename set<typename map<T, U>::node_t>::iterator begin() { return tmap.begin(); }
|
||||
typename set<typename map<T, U>::node_t>::iterator end() { return tmap.end(); }
|
||||
const typename set<typename map<T, U>::node_t>::iterator begin() const { return tmap.begin(); }
|
||||
const typename set<typename map<T, U>::node_t>::iterator end() const { return tmap.end(); }
|
||||
auto begin() -> typename set<typename map<T, U>::node_t>::iterator { return tmap.begin(); }
|
||||
auto end() -> typename set<typename map<T, U>::node_t>::iterator { return tmap.end(); }
|
||||
|
||||
auto begin() const -> const typename set<typename map<T, U>::node_t>::iterator { return tmap.begin(); }
|
||||
auto end() const -> const typename set<typename map<T, U>::node_t>::iterator { return tmap.end(); }
|
||||
|
||||
protected:
|
||||
map<T, U> tmap;
|
||||
|
|
|
@ -5,7 +5,7 @@ namespace nall {
|
|||
|
||||
namespace Matrix {
|
||||
|
||||
template<typename T> inline void Multiply(T* output, const T* xdata, unsigned xrows, unsigned xcols, const T* ydata, unsigned yrows, unsigned ycols) {
|
||||
template<typename T> inline auto Multiply(T* output, const T* xdata, unsigned xrows, unsigned xcols, const T* ydata, unsigned yrows, unsigned ycols) -> void {
|
||||
if(xcols != yrows) return;
|
||||
|
||||
for(unsigned y = 0; y < xrows; y++) {
|
||||
|
@ -19,7 +19,7 @@ template<typename T> inline void Multiply(T* output, const T* xdata, unsigned xr
|
|||
}
|
||||
}
|
||||
|
||||
template<typename T> inline vector<T> Multiply(const T* xdata, unsigned xrows, unsigned xcols, const T* ydata, unsigned yrows, unsigned ycols) {
|
||||
template<typename T> inline auto Multiply(const T* xdata, unsigned xrows, unsigned xcols, const T* ydata, unsigned yrows, unsigned ycols) -> vector<T> {
|
||||
vector<T> output;
|
||||
output.resize(xrows * ycols);
|
||||
Multiply(output.data(), xdata, xrows, xcols, ydata, yrows, ycols);
|
||||
|
|
|
@ -20,7 +20,7 @@ template<typename T> struct method {
|
|||
template<typename F> struct chain {
|
||||
chain(T& self, const F& f) : self(self), f(f) {}
|
||||
template<typename... P> auto operator()(P&&... p) -> T& {
|
||||
return f(self, std::forward<P>(p)...), self;
|
||||
return f(self, forward<P>(p)...), self;
|
||||
}
|
||||
private:
|
||||
T& self;
|
||||
|
@ -30,7 +30,7 @@ template<typename T> struct method {
|
|||
template<typename F> struct const_chain {
|
||||
const_chain(const T& self, const F& f) : self(self), f(f) {}
|
||||
template<typename... P> auto operator()(P&&... p) const -> const T& {
|
||||
return f(self, std::forward<P>(p)...), self;
|
||||
return f(self, forward<P>(p)...), self;
|
||||
}
|
||||
private:
|
||||
const T& self;
|
||||
|
@ -44,13 +44,13 @@ template<typename T> struct method {
|
|||
auto operator[](const F& f) const -> const_chain<F> { return const_chain<F>((const T&)*this, f); }
|
||||
|
||||
template<typename F, typename... P, typename = enable_if<is_function<F>>>
|
||||
auto operator()(const F& f, P&&... p) -> decltype(f((T&)*this, std::forward<P>(p)...)) {
|
||||
return f((T&)*this, std::forward<P>(p)...);
|
||||
auto operator()(const F& f, P&&... p) -> decltype(f((T&)*this, forward<P>(p)...)) {
|
||||
return f((T&)*this, forward<P>(p)...);
|
||||
}
|
||||
|
||||
template<typename F, typename... P, typename = enable_if<is_function<F>>>
|
||||
auto operator()(const F& f, P&&... p) const -> decltype(f((const T&)*this, std::forward<P>(p)...)) {
|
||||
return f((const T&)*this, std::forward<P>(p)...);
|
||||
auto operator()(const F& f, P&&... p) const -> decltype(f((const T&)*this, forward<P>(p)...)) {
|
||||
return f((const T&)*this, forward<P>(p)...);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -64,9 +64,9 @@ struct context {
|
|||
for(auto& item : list) {
|
||||
item.strip();
|
||||
if(item.match("f(?*) ?*")) {
|
||||
item.ltrim("f(");
|
||||
lstring part = item.split<1>(") ");
|
||||
lstring args = part[0].split<3>(";").strip();
|
||||
item.ltrim("f(", 1L);
|
||||
lstring part = item.split(") ", 1L);
|
||||
lstring args = part[0].split(";", 3L).strip();
|
||||
|
||||
unsigned length = eval(args(0, "0"));
|
||||
unsigned offset = eval(args(1, "0"));
|
||||
|
@ -85,10 +85,10 @@ struct context {
|
|||
}
|
||||
} else if(item.match("base64*")) {
|
||||
unsigned offset = 0;
|
||||
item.ltrim("base64");
|
||||
item.ltrim("base64", 1L);
|
||||
if(item.match("(?*) *")) {
|
||||
item.ltrim("(");
|
||||
lstring part = item.split<1>(") ");
|
||||
item.ltrim("(", 1L);
|
||||
lstring part = item.split(") ", 1L);
|
||||
offset = eval(part[0]);
|
||||
item = part(1, "");
|
||||
}
|
||||
|
@ -101,7 +101,7 @@ struct context {
|
|||
if(c == '_') buffer.append(offset + 63);
|
||||
}
|
||||
} else if(item.match("file *")) {
|
||||
item.ltrim("file ");
|
||||
item.ltrim("file ", 1L);
|
||||
item.strip();
|
||||
//...
|
||||
} else if(item.empty() == false) {
|
||||
|
@ -115,7 +115,7 @@ struct context {
|
|||
|
||||
lstring lines = data.split("\n");
|
||||
for(auto& line : lines) {
|
||||
lstring part = line.split<1>(":").strip();
|
||||
lstring part = line.split(":", 1L).strip();
|
||||
if(part.size() != 2) continue;
|
||||
|
||||
if(part[0] == "offset") offset = eval(part[1]);
|
||||
|
|
|
@ -28,7 +28,6 @@
|
|||
#include <nall/file.hpp>
|
||||
#include <nall/filemap.hpp>
|
||||
#include <nall/function.hpp>
|
||||
#include <nall/group.hpp>
|
||||
#include <nall/hashset.hpp>
|
||||
#include <nall/hid.hpp>
|
||||
#include <nall/image.hpp>
|
||||
|
|
153
nall/odbc.hpp
153
nall/odbc.hpp
|
@ -1,153 +0,0 @@
|
|||
#ifndef NALL_ODBC_HPP
|
||||
#define NALL_ODBC_HPP
|
||||
|
||||
//minimal wrapper for core ODBC v3 API
|
||||
//requires Windows or unixODBC
|
||||
|
||||
#include <nall/string.hpp>
|
||||
#include <nall/utility.hpp>
|
||||
|
||||
#include <sql.h>
|
||||
#include <sqltypes.h>
|
||||
#include <sqlext.h>
|
||||
|
||||
namespace nall {
|
||||
|
||||
struct ODBC {
|
||||
inline ODBC();
|
||||
inline ODBC(const string& database, const string& username, const string& password);
|
||||
inline ~ODBC();
|
||||
|
||||
inline bool connected();
|
||||
inline bool connect(const string& hostname, const string& username, const string& password);
|
||||
inline void disconnect();
|
||||
template<typename... Args> inline bool execute(Args&&... args);
|
||||
inline void release();
|
||||
inline unsigned rows();
|
||||
inline lstring read();
|
||||
|
||||
private:
|
||||
char* buffer = nullptr;
|
||||
SQLHANDLE sqlEnvironment = nullptr;
|
||||
SQLHANDLE sqlConnection = nullptr;
|
||||
SQLHANDLE sqlStatement = nullptr;
|
||||
};
|
||||
|
||||
ODBC::ODBC() {
|
||||
auto result = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &sqlEnvironment);
|
||||
if(result != SQL_SUCCESS && result != SQL_SUCCESS_WITH_INFO) return;
|
||||
|
||||
SQLSetEnvAttr(sqlEnvironment, SQL_ATTR_ODBC_VERSION, (void*)SQL_OV_ODBC3, 0);
|
||||
buffer = new char[65536]();
|
||||
}
|
||||
|
||||
ODBC::ODBC(const string& database, const string& username, const string& password) : ODBC() {
|
||||
connect(database, username, password);
|
||||
}
|
||||
|
||||
ODBC::~ODBC() {
|
||||
if(sqlEnvironment) {
|
||||
disconnect();
|
||||
SQLFreeHandle(SQL_HANDLE_ENV, sqlEnvironment);
|
||||
sqlEnvironment = nullptr;
|
||||
|
||||
delete[] buffer;
|
||||
buffer = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
bool ODBC::connected() {
|
||||
return sqlConnection;
|
||||
}
|
||||
|
||||
bool ODBC::connect(const string& hostname, const string& username, const string& password) {
|
||||
if(!sqlEnvironment) return false;
|
||||
disconnect();
|
||||
|
||||
auto result = SQLAllocHandle(SQL_HANDLE_DBC, sqlEnvironment, &sqlConnection);
|
||||
if(result != SQL_SUCCESS && result != SQL_SUCCESS_WITH_INFO) return false;
|
||||
|
||||
SQLSetConnectAttr(sqlConnection, SQL_LOGIN_TIMEOUT, (SQLPOINTER)5, 0);
|
||||
result = SQLConnectA(sqlConnection,
|
||||
(SQLCHAR*)(const char*)hostname, SQL_NTS,
|
||||
(SQLCHAR*)(const char*)username, SQL_NTS,
|
||||
(SQLCHAR*)(const char*)password, SQL_NTS
|
||||
);
|
||||
if(result != SQL_SUCCESS && result != SQL_SUCCESS_WITH_INFO) {
|
||||
disconnect();
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void ODBC::disconnect() {
|
||||
if(sqlConnection) {
|
||||
release();
|
||||
SQLDisconnect(sqlConnection);
|
||||
SQLFreeHandle(SQL_HANDLE_DBC, sqlConnection);
|
||||
sqlConnection = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename... Args>
|
||||
bool ODBC::execute(Args&&... args) {
|
||||
string statement({args...});
|
||||
|
||||
if(!sqlConnection) return false;
|
||||
release();
|
||||
|
||||
auto result = SQLAllocHandle(SQL_HANDLE_STMT, sqlConnection, &sqlStatement);
|
||||
if(result != SQL_SUCCESS && result != SQL_SUCCESS_WITH_INFO) return false;
|
||||
|
||||
result = SQLExecDirectA(sqlStatement, (SQLCHAR*)(const char*)statement, SQL_NTS);
|
||||
if(result != SQL_SUCCESS && result != SQL_SUCCESS_WITH_INFO) {
|
||||
release();
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void ODBC::release() {
|
||||
if(sqlStatement) {
|
||||
SQLFreeHandle(SQL_HANDLE_STMT, sqlStatement);
|
||||
sqlStatement = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
//valid after update, insert or delete
|
||||
unsigned ODBC::rows() {
|
||||
if(!sqlStatement) return 0;
|
||||
|
||||
SQLLEN sqlRows = 0;
|
||||
auto result = SQLRowCount(sqlStatement, &sqlRows);
|
||||
if(result != SQL_SUCCESS && result != SQL_SUCCESS_WITH_INFO) return 0;
|
||||
|
||||
return sqlRows;
|
||||
}
|
||||
|
||||
//valid after select
|
||||
lstring ODBC::read() {
|
||||
if(!sqlStatement) return {};
|
||||
|
||||
auto result = SQLFetch(sqlStatement);
|
||||
if(result != SQL_SUCCESS && result != SQL_SUCCESS_WITH_INFO) return {};
|
||||
|
||||
SQLSMALLINT sqlColumns = 0;
|
||||
result = SQLNumResultCols(sqlStatement, &sqlColumns);
|
||||
if(result != SQL_SUCCESS && result != SQL_SUCCESS_WITH_INFO) return {};
|
||||
|
||||
lstring data;
|
||||
for(unsigned column = 0; column < sqlColumns; column++) {
|
||||
SQLLEN length = 0;
|
||||
SQLGetData(sqlStatement, 1 + column, SQL_C_CHAR, buffer, 65535, &length);
|
||||
data.append(buffer);
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
|
@ -55,7 +55,7 @@ struct shared_memory {
|
|||
auto create(const string& name, unsigned size) -> bool {
|
||||
reset();
|
||||
|
||||
_name = {"/nall::", string{name}.transform("/", ":")};
|
||||
_name = {"/nall-", string{name}.transform("/:", "--")};
|
||||
_size = size;
|
||||
|
||||
//O_CREAT | O_EXCL seems to throw ENOENT even when semaphore does not exist ...
|
||||
|
@ -102,7 +102,7 @@ struct shared_memory {
|
|||
auto open(const string& name, unsigned size) -> bool {
|
||||
reset();
|
||||
|
||||
_name = {"/nall::", string{name}.transform("/", ":")};
|
||||
_name = {"/nall-", string{name}.transform("/:", "--")};
|
||||
_size = size;
|
||||
|
||||
_semaphore = sem_open(_name, 0, 0644);
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
|
||||
namespace nall {
|
||||
|
||||
template<typename type_t> void priority_queue_nocallback(type_t) {}
|
||||
template<typename type_t> auto priority_queue_nocallback(type_t) -> void {}
|
||||
|
||||
//priority queue implementation using binary min-heap array;
|
||||
//does not require normalize() function.
|
||||
|
@ -16,14 +16,27 @@ template<typename type_t> void priority_queue_nocallback(type_t) {}
|
|||
//O(log n) append (enqueue)
|
||||
//O(log n) remove (dequeue)
|
||||
template<typename type_t> struct priority_queue {
|
||||
inline void tick(unsigned ticks) {
|
||||
priority_queue(unsigned size, function<void (type_t)> callback = &priority_queue_nocallback<type_t>) : callback(callback) {
|
||||
heap = new heap_t[size];
|
||||
heapcapacity = size;
|
||||
reset();
|
||||
}
|
||||
|
||||
~priority_queue() {
|
||||
delete[] heap;
|
||||
}
|
||||
|
||||
priority_queue(const priority_queue&) = delete;
|
||||
auto operator=(const priority_queue&) -> priority_queue& = delete;
|
||||
|
||||
inline auto tick(unsigned ticks) -> void {
|
||||
basecounter += ticks;
|
||||
while(heapsize && gte(basecounter, heap[0].counter)) callback(dequeue());
|
||||
}
|
||||
|
||||
//counter is relative to current time (eg enqueue(64, ...) fires in 64 ticks);
|
||||
//counter cannot exceed std::numeric_limits<unsigned>::max() >> 1.
|
||||
void enqueue(unsigned counter, type_t event) {
|
||||
auto enqueue(unsigned counter, type_t event) -> void {
|
||||
unsigned child = heapsize++;
|
||||
counter += basecounter;
|
||||
|
||||
|
@ -40,7 +53,7 @@ template<typename type_t> struct priority_queue {
|
|||
heap[child].event = event;
|
||||
}
|
||||
|
||||
type_t dequeue() {
|
||||
auto dequeue() -> type_t {
|
||||
type_t event(heap[0].event);
|
||||
unsigned parent = 0;
|
||||
unsigned counter = heap[--heapsize].counter;
|
||||
|
@ -61,12 +74,12 @@ template<typename type_t> struct priority_queue {
|
|||
return event;
|
||||
}
|
||||
|
||||
void reset() {
|
||||
auto reset() -> void {
|
||||
basecounter = 0;
|
||||
heapsize = 0;
|
||||
}
|
||||
|
||||
void serialize(serializer& s) {
|
||||
auto serialize(serializer& s) -> void {
|
||||
s.integer(basecounter);
|
||||
s.integer(heapsize);
|
||||
for(unsigned n = 0; n < heapcapacity; n++) {
|
||||
|
@ -75,20 +88,6 @@ template<typename type_t> struct priority_queue {
|
|||
}
|
||||
}
|
||||
|
||||
priority_queue(unsigned size, function<void (type_t)> callback = &priority_queue_nocallback<type_t>)
|
||||
: callback(callback) {
|
||||
heap = new heap_t[size];
|
||||
heapcapacity = size;
|
||||
reset();
|
||||
}
|
||||
|
||||
~priority_queue() {
|
||||
delete[] heap;
|
||||
}
|
||||
|
||||
priority_queue& operator=(const priority_queue&) = delete;
|
||||
priority_queue(const priority_queue&) = delete;
|
||||
|
||||
private:
|
||||
function<void (type_t)> callback;
|
||||
unsigned basecounter;
|
||||
|
@ -100,7 +99,7 @@ private:
|
|||
} *heap;
|
||||
|
||||
//return true if x is greater than or equal to y
|
||||
inline bool gte(unsigned x, unsigned y) {
|
||||
inline auto gte(unsigned x, unsigned y) -> bool {
|
||||
return x - y < (std::numeric_limits<unsigned>::max() >> 1);
|
||||
}
|
||||
};
|
||||
|
|
|
@ -5,36 +5,36 @@ namespace nall {
|
|||
|
||||
template<typename C> struct property {
|
||||
template<typename T> struct readonly {
|
||||
const T* operator->() const { return &value; }
|
||||
const T& operator()() const { return value; }
|
||||
auto operator->() const -> const T* { return &value; }
|
||||
auto operator()() const -> const T& { return value; }
|
||||
operator const T&() const { return value; }
|
||||
private:
|
||||
T* operator->() { return &value; }
|
||||
auto operator->() -> T* { return &value; }
|
||||
operator T&() { return value; }
|
||||
const T& operator=(const T& value_) { return value = value_; }
|
||||
auto operator=(const T& value_) -> const T& { return value = value_; }
|
||||
T value;
|
||||
friend C;
|
||||
};
|
||||
|
||||
template<typename T> struct writeonly {
|
||||
void operator=(const T& value_) { value = value_; }
|
||||
auto operator=(const T& value_) -> void { value = value_; }
|
||||
private:
|
||||
const T* operator->() const { return &value; }
|
||||
const T& operator()() const { return value; }
|
||||
auto operator->() const -> const T* { return &value; }
|
||||
auto operator()() const -> const T& { return value; }
|
||||
operator const T&() const { return value; }
|
||||
T* operator->() { return &value; }
|
||||
auto operator->() -> T* { return &value; }
|
||||
operator T&() { return value; }
|
||||
T value;
|
||||
friend C;
|
||||
};
|
||||
|
||||
template<typename T> struct readwrite {
|
||||
const T* operator->() const { return &value; }
|
||||
const T& operator()() const { return value; }
|
||||
auto operator->() const -> const T* { return &value; }
|
||||
auto operator()() const -> const T& { return value; }
|
||||
operator const T&() const { return value; }
|
||||
T* operator->() { return &value; }
|
||||
auto operator->() -> T* { return &value; }
|
||||
operator T&() { return value; }
|
||||
const T& operator=(const T& value_) { return value = value_; }
|
||||
auto operator=(const T& value_) -> const T& { return value = value_; }
|
||||
T value;
|
||||
};
|
||||
};
|
||||
|
|
|
@ -7,23 +7,23 @@
|
|||
namespace nall {
|
||||
|
||||
struct RandomNumberGenerator {
|
||||
virtual void seed(uint64_t) = 0;
|
||||
virtual uint64_t operator()() = 0;
|
||||
virtual void serialize(serializer&) = 0;
|
||||
virtual auto seed(uint64_t) -> void = 0;
|
||||
virtual auto operator()() -> uint64_t = 0;
|
||||
virtual auto serialize(serializer&) -> void = 0;
|
||||
};
|
||||
|
||||
//Galois LFSR using CRC64 polynomials
|
||||
struct LinearFeedbackShiftRegisterGenerator : RandomNumberGenerator {
|
||||
void seed(uint64_t seed) {
|
||||
auto seed(uint64_t seed) -> void {
|
||||
lfsr = seed;
|
||||
for(unsigned n = 0; n < 8; n++) operator()();
|
||||
}
|
||||
|
||||
uint64_t operator()() {
|
||||
auto operator()() -> uint64_t {
|
||||
return lfsr = (lfsr >> 1) ^ (-(lfsr & 1) & crc64jones);
|
||||
}
|
||||
|
||||
void serialize(serializer& s) {
|
||||
auto serialize(serializer& s) -> void {
|
||||
s.integer(lfsr);
|
||||
}
|
||||
|
||||
|
@ -33,7 +33,7 @@ private:
|
|||
uint64_t lfsr = crc64ecma;
|
||||
};
|
||||
|
||||
inline uint64_t random() {
|
||||
inline auto random() -> uint64_t {
|
||||
static LinearFeedbackShiftRegisterGenerator lfsr;
|
||||
return lfsr();
|
||||
}
|
||||
|
|
|
@ -5,41 +5,41 @@ namespace nall {
|
|||
|
||||
struct range_t {
|
||||
struct iterator {
|
||||
signed operator*() const { return position; }
|
||||
bool operator!=(const iterator& source) const { return step > 0 ? position < source.position : position > source.position; }
|
||||
iterator& operator++() { position += step; return *this; }
|
||||
iterator(signed position, signed step = 0) : position(position), step(step) {}
|
||||
auto operator*() const -> signed { return position; }
|
||||
auto operator!=(const iterator& source) const -> bool { return step > 0 ? position < source.position : position > source.position; }
|
||||
auto operator++() -> iterator& { position += step; return *this; }
|
||||
|
||||
private:
|
||||
signed position;
|
||||
const signed step;
|
||||
};
|
||||
|
||||
const iterator begin() const { return iterator(origin, stride); }
|
||||
const iterator end() const { return iterator(target); }
|
||||
auto begin() const -> const iterator { return iterator(origin, stride); }
|
||||
auto end() const -> const iterator { return iterator(target); }
|
||||
|
||||
signed origin;
|
||||
signed target;
|
||||
signed stride;
|
||||
};
|
||||
|
||||
inline range_t range(signed size) {
|
||||
inline auto range(signed size) {
|
||||
return range_t{0, size, 1};
|
||||
}
|
||||
|
||||
inline range_t range(signed offset, signed size) {
|
||||
inline auto range(signed offset, signed size) {
|
||||
return range_t{offset, size, 1};
|
||||
}
|
||||
|
||||
inline range_t range(signed offset, signed size, signed step) {
|
||||
inline auto range(signed offset, signed size, signed step) {
|
||||
return range_t{offset, size, step};
|
||||
}
|
||||
|
||||
inline range_t range_reverse(signed size) {
|
||||
inline auto rangeReverse(signed size) {
|
||||
return range_t{size - 1, -1, -1};
|
||||
}
|
||||
|
||||
template<typename T> inline range_t range(const vector<T>& container) {
|
||||
template<typename T> inline auto range(const vector<T>& container) {
|
||||
return range_t{0, (signed)container.size(), 1};
|
||||
}
|
||||
|
||||
|
|
|
@ -17,7 +17,16 @@
|
|||
namespace nall {
|
||||
|
||||
struct serial {
|
||||
bool readable() {
|
||||
serial() {
|
||||
port = -1;
|
||||
port_open = false;
|
||||
}
|
||||
|
||||
~serial() {
|
||||
close();
|
||||
}
|
||||
|
||||
auto readable() -> bool {
|
||||
if(port_open == false) return false;
|
||||
fd_set fdset;
|
||||
FD_ZERO(&fdset);
|
||||
|
@ -31,12 +40,12 @@ struct serial {
|
|||
}
|
||||
|
||||
//-1 on error, otherwise return bytes read
|
||||
int read(uint8_t* data, unsigned length) {
|
||||
auto read(uint8_t* data, unsigned length) -> int {
|
||||
if(port_open == false) return -1;
|
||||
return ::read(port, (void*)data, length);
|
||||
}
|
||||
|
||||
bool writable() {
|
||||
auto writable() -> bool {
|
||||
if(port_open == false) return false;
|
||||
fd_set fdset;
|
||||
FD_ZERO(&fdset);
|
||||
|
@ -50,12 +59,12 @@ struct serial {
|
|||
}
|
||||
|
||||
//-1 on error, otherwise return bytes written
|
||||
int write(const uint8_t* data, unsigned length) {
|
||||
auto write(const uint8_t* data, unsigned length) -> int {
|
||||
if(port_open == false) return -1;
|
||||
return ::write(port, (void*)data, length);
|
||||
}
|
||||
|
||||
bool open(const string& portname, unsigned rate, bool flowcontrol) {
|
||||
auto open(const string& portname, unsigned rate, bool flowcontrol) -> bool {
|
||||
close();
|
||||
|
||||
port = ::open(portname, O_RDWR | O_NOCTTY | O_NDELAY | O_NONBLOCK);
|
||||
|
@ -86,7 +95,7 @@ struct serial {
|
|||
return port_open = true;
|
||||
}
|
||||
|
||||
void close() {
|
||||
auto close() -> void {
|
||||
if(port != -1) {
|
||||
tcdrain(port);
|
||||
if(port_open == true) {
|
||||
|
@ -98,15 +107,6 @@ struct serial {
|
|||
}
|
||||
}
|
||||
|
||||
serial() {
|
||||
port = -1;
|
||||
port_open = false;
|
||||
}
|
||||
|
||||
~serial() {
|
||||
close();
|
||||
}
|
||||
|
||||
private:
|
||||
int port;
|
||||
bool port_open;
|
||||
|
|
|
@ -23,31 +23,31 @@ struct serializer;
|
|||
|
||||
template<typename T>
|
||||
struct has_serialize {
|
||||
template<typename C> static char test(decltype(std::declval<C>().serialize(std::declval<serializer&>()))*);
|
||||
template<typename C> static long test(...);
|
||||
template<typename C> static auto test(decltype(std::declval<C>().serialize(std::declval<serializer&>()))*) -> char;
|
||||
template<typename C> static auto test(...) -> long;
|
||||
static const bool value = sizeof(test<T>(0)) == sizeof(char);
|
||||
};
|
||||
|
||||
struct serializer {
|
||||
enum mode_t { Load, Save, Size };
|
||||
|
||||
mode_t mode() const {
|
||||
auto mode() const -> mode_t {
|
||||
return _mode;
|
||||
}
|
||||
|
||||
const uint8_t* data() const {
|
||||
auto data() const -> const uint8_t* {
|
||||
return _data;
|
||||
}
|
||||
|
||||
unsigned size() const {
|
||||
auto size() const -> unsigned {
|
||||
return _size;
|
||||
}
|
||||
|
||||
unsigned capacity() const {
|
||||
auto capacity() const -> unsigned {
|
||||
return _capacity;
|
||||
}
|
||||
|
||||
template<typename T> serializer& floatingpoint(T& value) {
|
||||
template<typename T> auto floatingpoint(T& value) -> serializer& {
|
||||
enum { size = sizeof(T) };
|
||||
//this is rather dangerous, and not cross-platform safe;
|
||||
//but there is no standardized way to export FP-values
|
||||
|
@ -62,7 +62,7 @@ struct serializer {
|
|||
return *this;
|
||||
}
|
||||
|
||||
template<typename T> serializer& integer(T& value) {
|
||||
template<typename T> auto integer(T& value) -> serializer& {
|
||||
enum { size = std::is_same<bool, T>::value ? 1 : sizeof(T) };
|
||||
if(_mode == Save) {
|
||||
for(unsigned n = 0; n < size; n++) _data[_size++] = (uintmax_t)value >> (n << 3);
|
||||
|
@ -75,23 +75,23 @@ struct serializer {
|
|||
return *this;
|
||||
}
|
||||
|
||||
template<typename T, int N> serializer& array(T (&array)[N]) {
|
||||
template<typename T, int N> auto array(T (&array)[N]) -> serializer& {
|
||||
for(unsigned n = 0; n < N; n++) operator()(array[n]);
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename T> serializer& array(T array, unsigned size) {
|
||||
template<typename T> auto array(T array, unsigned size) -> serializer& {
|
||||
for(unsigned n = 0; n < size; n++) operator()(array[n]);
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename T> serializer& operator()(T& value, typename std::enable_if<has_serialize<T>::value>::type* = 0) { value.serialize(*this); return *this; }
|
||||
template<typename T> serializer& operator()(T& value, typename std::enable_if<std::is_integral<T>::value>::type* = 0) { return integer(value); }
|
||||
template<typename T> serializer& operator()(T& value, typename std::enable_if<std::is_floating_point<T>::value>::type* = 0) { return floatingpoint(value); }
|
||||
template<typename T> serializer& operator()(T& value, typename std::enable_if<std::is_array<T>::value>::type* = 0) { return array(value); }
|
||||
template<typename T> serializer& operator()(T& value, unsigned size, typename std::enable_if<std::is_pointer<T>::value>::type* = 0) { return array(value, size); }
|
||||
template<typename T> auto operator()(T& value, typename std::enable_if<has_serialize<T>::value>::type* = 0) -> serializer& { value.serialize(*this); return *this; }
|
||||
template<typename T> auto operator()(T& value, typename std::enable_if<std::is_integral<T>::value>::type* = 0) -> serializer& { return integer(value); }
|
||||
template<typename T> auto operator()(T& value, typename std::enable_if<std::is_floating_point<T>::value>::type* = 0) -> serializer& { return floatingpoint(value); }
|
||||
template<typename T> auto operator()(T& value, typename std::enable_if<std::is_array<T>::value>::type* = 0) -> serializer& { return array(value); }
|
||||
template<typename T> auto operator()(T& value, unsigned size, typename std::enable_if<std::is_pointer<T>::value>::type* = 0) -> serializer& { return array(value, size); }
|
||||
|
||||
serializer& operator=(const serializer& s) {
|
||||
auto operator=(const serializer& s) -> serializer& {
|
||||
if(_data) delete[] _data;
|
||||
|
||||
_mode = s._mode;
|
||||
|
@ -103,7 +103,7 @@ struct serializer {
|
|||
return *this;
|
||||
}
|
||||
|
||||
serializer& operator=(serializer&& s) {
|
||||
auto operator=(serializer&& s) -> serializer& {
|
||||
if(_data) delete[] _data;
|
||||
|
||||
_mode = s._mode;
|
||||
|
@ -117,7 +117,7 @@ struct serializer {
|
|||
|
||||
serializer() = default;
|
||||
serializer(const serializer& s) { operator=(s); }
|
||||
serializer(serializer&& s) { operator=(std::move(s)); }
|
||||
serializer(serializer&& s) { operator=(move(s)); }
|
||||
|
||||
serializer(unsigned capacity) {
|
||||
_mode = Save;
|
||||
|
|
68
nall/set.hpp
68
nall/set.hpp
|
@ -29,33 +29,33 @@ template<typename T> struct set {
|
|||
node_t* root = nullptr;
|
||||
unsigned nodes = 0;
|
||||
|
||||
set& operator=(const set& source) { copy(source); return *this; }
|
||||
set& operator=(set&& source) { move(std::move(source)); return *this; }
|
||||
auto operator=(const set& source) -> set& { copy(source); return *this; }
|
||||
auto operator=(set&& source) -> set& { move(std::move(source)); return *this; }
|
||||
set(const set& source) { operator=(source); }
|
||||
set(set&& source) { operator=(std::move(source)); }
|
||||
set(set&& source) { operator=(move(source)); }
|
||||
set(std::initializer_list<T> list) { for(auto& value : list) insert(value); }
|
||||
set() = default;
|
||||
~set() { reset(); }
|
||||
|
||||
unsigned size() const { return nodes; }
|
||||
bool empty() const { return nodes == 0; }
|
||||
auto size() const -> unsigned { return nodes; }
|
||||
auto empty() const -> bool { return nodes == 0; }
|
||||
|
||||
void reset() {
|
||||
auto reset() -> void {
|
||||
reset(root);
|
||||
nodes = 0;
|
||||
}
|
||||
|
||||
maybe<T&> find(const T& value) {
|
||||
auto find(const T& value) -> maybe<T&> {
|
||||
if(node_t* node = find(root, value)) return node->value;
|
||||
return nothing;
|
||||
}
|
||||
|
||||
maybe<const T&> find(const T& value) const {
|
||||
auto find(const T& value) const -> maybe<const T&> {
|
||||
if(node_t* node = find(root, value)) return node->value;
|
||||
return nothing;
|
||||
}
|
||||
|
||||
maybe<T&> insert(const T& value) {
|
||||
auto insert(const T& value) -> maybe<T&> {
|
||||
unsigned count = size();
|
||||
node_t* v = insert(root, value);
|
||||
root->red = 0;
|
||||
|
@ -63,13 +63,13 @@ template<typename T> struct set {
|
|||
return v->value;
|
||||
}
|
||||
|
||||
template<typename... Args> bool insert(const T& value, Args&&... args) {
|
||||
template<typename... Args> auto insert(const T& value, Args&&... args) -> bool {
|
||||
bool result = insert(value);
|
||||
insert(std::forward<Args>(args)...) | result;
|
||||
insert(forward<Args>(args)...) | result;
|
||||
return result;
|
||||
}
|
||||
|
||||
bool remove(const T& value) {
|
||||
auto remove(const T& value) -> bool {
|
||||
unsigned count = size();
|
||||
bool done = 0;
|
||||
remove(root, &value, done);
|
||||
|
@ -77,15 +77,15 @@ template<typename T> struct set {
|
|||
return size() < count;
|
||||
}
|
||||
|
||||
template<typename... Args> bool remove(const T& value, Args&&... args) {
|
||||
template<typename... Args> auto remove(const T& value, Args&&... args) -> bool {
|
||||
bool result = remove(value);
|
||||
return remove(std::forward<Args>(args)...) | result;
|
||||
return remove(forward<Args>(args)...) | result;
|
||||
}
|
||||
|
||||
struct base_iterator {
|
||||
bool operator!=(const base_iterator& source) const { return position != source.position; }
|
||||
auto operator!=(const base_iterator& source) const -> bool { return position != source.position; }
|
||||
|
||||
base_iterator& operator++() {
|
||||
auto operator++() -> base_iterator& {
|
||||
if(++position >= source.size()) { position = source.size(); return *this; }
|
||||
|
||||
if(stack.last()->link[1]) {
|
||||
|
@ -115,23 +115,23 @@ template<typename T> struct set {
|
|||
};
|
||||
|
||||
struct iterator : base_iterator {
|
||||
T& operator*() const { return base_iterator::stack.last()->value; }
|
||||
iterator(const set& source, unsigned position) : base_iterator(source, position) {}
|
||||
auto operator*() const -> T& { return base_iterator::stack.last()->value; }
|
||||
};
|
||||
|
||||
iterator begin() { return iterator(*this, 0); }
|
||||
iterator end() { return iterator(*this, size()); }
|
||||
auto begin() -> iterator { return iterator(*this, 0); }
|
||||
auto end() -> iterator { return iterator(*this, size()); }
|
||||
|
||||
struct const_iterator : base_iterator {
|
||||
const T& operator*() const { return base_iterator::stack.last()->value; }
|
||||
const_iterator(const set& source, unsigned position) : base_iterator(source, position) {}
|
||||
auto operator*() const -> const T& { return base_iterator::stack.last()->value; }
|
||||
};
|
||||
|
||||
const const_iterator begin() const { return const_iterator(*this, 0); }
|
||||
const const_iterator end() const { return const_iterator(*this, size()); }
|
||||
auto begin() const -> const const_iterator { return const_iterator(*this, 0); }
|
||||
auto end() const -> const const_iterator { return const_iterator(*this, size()); }
|
||||
|
||||
private:
|
||||
void reset(node_t*& node) {
|
||||
auto reset(node_t*& node) -> void {
|
||||
if(!node) return;
|
||||
if(node->link[0]) reset(node->link[0]);
|
||||
if(node->link[1]) reset(node->link[1]);
|
||||
|
@ -139,13 +139,13 @@ private:
|
|||
node = nullptr;
|
||||
}
|
||||
|
||||
void copy(const set& source) {
|
||||
auto copy(const set& source) -> void {
|
||||
reset();
|
||||
copy(root, source.root);
|
||||
nodes = source.nodes;
|
||||
}
|
||||
|
||||
void copy(node_t*& target, const node_t* source) {
|
||||
auto copy(node_t*& target, const node_t* source) -> void {
|
||||
if(!source) return;
|
||||
target = new node_t(source->value);
|
||||
target->red = source->red;
|
||||
|
@ -153,23 +153,23 @@ private:
|
|||
copy(target->link[1], source->link[1]);
|
||||
}
|
||||
|
||||
void move(set&& source) {
|
||||
auto move(set&& source) -> void {
|
||||
root = source.root;
|
||||
nodes = source.nodes;
|
||||
source.root = nullptr;
|
||||
source.nodes = 0;
|
||||
}
|
||||
|
||||
node_t* find(node_t* node, const T& value) const {
|
||||
auto find(node_t* node, const T& value) const -> node_t* {
|
||||
if(node == nullptr) return nullptr;
|
||||
if(node->value == value) return node;
|
||||
return find(node->link[node->value < value], value);
|
||||
}
|
||||
|
||||
bool red(node_t* node) const { return node && node->red; }
|
||||
bool black(node_t* node) const { return !red(node); }
|
||||
auto red(node_t* node) const -> bool { return node && node->red; }
|
||||
auto black(node_t* node) const -> bool { return !red(node); }
|
||||
|
||||
void rotate(node_t*& a, bool dir) {
|
||||
auto rotate(node_t*& a, bool dir) -> void {
|
||||
node_t*& b = a->link[!dir];
|
||||
node_t*& c = b->link[dir];
|
||||
a->red = 1, b->red = 0;
|
||||
|
@ -177,12 +177,12 @@ private:
|
|||
std::swap(b, c);
|
||||
}
|
||||
|
||||
void rotateTwice(node_t*& node, bool dir) {
|
||||
auto rotateTwice(node_t*& node, bool dir) -> void {
|
||||
rotate(node->link[!dir], !dir);
|
||||
rotate(node, dir);
|
||||
}
|
||||
|
||||
node_t* insert(node_t*& node, const T& value) {
|
||||
auto insert(node_t*& node, const T& value) -> node_t* {
|
||||
if(!node) { nodes++; node = new node_t(value); return node; }
|
||||
if(node->value == value) { node->value = value; return node; } //prevent duplicate entries
|
||||
|
||||
|
@ -203,7 +203,7 @@ private:
|
|||
return v;
|
||||
}
|
||||
|
||||
void balance(node_t*& node, bool dir, bool& done) {
|
||||
auto balance(node_t*& node, bool dir, bool& done) -> void {
|
||||
node_t* p = node;
|
||||
node_t* s = node->link[!dir];
|
||||
if(!s) return;
|
||||
|
@ -234,7 +234,7 @@ private:
|
|||
}
|
||||
}
|
||||
|
||||
void remove(node_t*& node, const T* value, bool& done) {
|
||||
auto remove(node_t*& node, const T* value, bool& done) -> void {
|
||||
if(!node) { done = 1; return; }
|
||||
|
||||
if(node->value == *value) {
|
||||
|
|
|
@ -21,22 +21,22 @@ namespace nall {
|
|||
struct SMTP {
|
||||
enum class Format : unsigned { Plain, HTML };
|
||||
|
||||
inline void server(string server, uint16_t port = 25);
|
||||
inline void from(string mail, string name = "");
|
||||
inline void to(string mail, string name = "");
|
||||
inline void cc(string mail, string name = "");
|
||||
inline void bcc(string mail, string name = "");
|
||||
inline void attachment(const uint8_t* data, unsigned size, string name);
|
||||
inline bool attachment(string filename, string name = "");
|
||||
inline void subject(string subject);
|
||||
inline void body(string body, Format format = Format::Plain);
|
||||
inline auto server(string server, uint16_t port = 25) -> void;
|
||||
inline auto from(string mail, string name = "") -> void;
|
||||
inline auto to(string mail, string name = "") -> void;
|
||||
inline auto cc(string mail, string name = "") -> void;
|
||||
inline auto bcc(string mail, string name = "") -> void;
|
||||
inline auto attachment(const uint8_t* data, unsigned size, string name) -> void;
|
||||
inline auto attachment(string filename, string name = "") -> bool;
|
||||
inline auto subject(string subject) -> void;
|
||||
inline auto body(string body, Format format = Format::Plain) -> void;
|
||||
|
||||
inline bool send();
|
||||
inline string message();
|
||||
inline string response();
|
||||
inline auto send() -> bool;
|
||||
inline auto message() -> string;
|
||||
inline auto response() -> string;
|
||||
|
||||
#ifdef _WIN32
|
||||
inline int close(int);
|
||||
#if defined(API_WINDOWS)
|
||||
inline auto close(int) -> int;
|
||||
inline SMTP();
|
||||
#endif
|
||||
|
||||
|
@ -65,44 +65,44 @@ private:
|
|||
string response;
|
||||
} info;
|
||||
|
||||
inline bool send(int sock, const string& text);
|
||||
inline string recv(int sock);
|
||||
inline string boundary();
|
||||
inline string filename(const string& filename);
|
||||
inline string contact(const Information::Contact& contact);
|
||||
inline string contacts(const vector<Information::Contact>& contacts);
|
||||
inline string split(const string& text);
|
||||
inline auto send(int sock, const string& text) -> bool;
|
||||
inline auto recv(int sock) -> string;
|
||||
inline auto boundary() -> string;
|
||||
inline auto filename(const string& filename) -> string;
|
||||
inline auto contact(const Information::Contact& contact) -> string;
|
||||
inline auto contacts(const vector<Information::Contact>& contacts) -> string;
|
||||
inline auto split(const string& text) -> string;
|
||||
};
|
||||
|
||||
void SMTP::server(string server, uint16_t port) {
|
||||
auto SMTP::server(string server, uint16_t port) -> void {
|
||||
info.server = server;
|
||||
info.port = port;
|
||||
}
|
||||
|
||||
void SMTP::from(string mail, string name) {
|
||||
auto SMTP::from(string mail, string name) -> void {
|
||||
info.from = {mail, name};
|
||||
}
|
||||
|
||||
void SMTP::to(string mail, string name) {
|
||||
auto SMTP::to(string mail, string name) -> void {
|
||||
info.to.append({mail, name});
|
||||
}
|
||||
|
||||
void SMTP::cc(string mail, string name) {
|
||||
auto SMTP::cc(string mail, string name) -> void {
|
||||
info.cc.append({mail, name});
|
||||
}
|
||||
|
||||
void SMTP::bcc(string mail, string name) {
|
||||
auto SMTP::bcc(string mail, string name) -> void {
|
||||
info.bcc.append({mail, name});
|
||||
}
|
||||
|
||||
void SMTP::attachment(const uint8_t* data, unsigned size, string name) {
|
||||
auto SMTP::attachment(const uint8_t* data, unsigned size, string name) -> void {
|
||||
vector<uint8_t> buffer;
|
||||
buffer.resize(size);
|
||||
memcpy(buffer.data(), data, size);
|
||||
info.attachments.append({std::move(buffer), name});
|
||||
}
|
||||
|
||||
bool SMTP::attachment(string filename, string name) {
|
||||
auto SMTP::attachment(string filename, string name) -> bool {
|
||||
if(!file::exists(filename)) return false;
|
||||
if(name == "") name = notdir(filename);
|
||||
auto buffer = file::read(filename);
|
||||
|
@ -110,16 +110,16 @@ bool SMTP::attachment(string filename, string name) {
|
|||
return true;
|
||||
}
|
||||
|
||||
void SMTP::subject(string subject) {
|
||||
auto SMTP::subject(string subject) -> void {
|
||||
info.subject = subject;
|
||||
}
|
||||
|
||||
void SMTP::body(string body, Format format) {
|
||||
auto SMTP::body(string body, Format format) -> void {
|
||||
info.body = body;
|
||||
info.format = format;
|
||||
}
|
||||
|
||||
bool SMTP::send() {
|
||||
auto SMTP::send() -> bool {
|
||||
info.message.append("From: =?UTF-8?B?", Base64::encode(contact(info.from)), "?=\r\n");
|
||||
info.message.append("To: =?UTF-8?B?", Base64::encode(contacts(info.to)), "?=\r\n");
|
||||
info.message.append("Cc: =?UTF-8?B?", Base64::encode(contacts(info.cc)), "?=\r\n");
|
||||
|
@ -214,15 +214,15 @@ bool SMTP::send() {
|
|||
return true;
|
||||
}
|
||||
|
||||
string SMTP::message() {
|
||||
auto SMTP::message() -> string {
|
||||
return info.message;
|
||||
}
|
||||
|
||||
string SMTP::response() {
|
||||
auto SMTP::response() -> string {
|
||||
return info.response;
|
||||
}
|
||||
|
||||
bool SMTP::send(int sock, const string& text) {
|
||||
auto SMTP::send(int sock, const string& text) -> bool {
|
||||
const char* data = text.data();
|
||||
unsigned size = text.size();
|
||||
while(size) {
|
||||
|
@ -234,7 +234,7 @@ bool SMTP::send(int sock, const string& text) {
|
|||
return true;
|
||||
}
|
||||
|
||||
string SMTP::recv(int sock) {
|
||||
auto SMTP::recv(int sock) -> string {
|
||||
vector<uint8_t> buffer;
|
||||
while(true) {
|
||||
char c;
|
||||
|
@ -246,7 +246,7 @@ string SMTP::recv(int sock) {
|
|||
return buffer;
|
||||
}
|
||||
|
||||
string SMTP::boundary() {
|
||||
auto SMTP::boundary() -> string {
|
||||
random_lfsr random;
|
||||
random.seed(time(0));
|
||||
string boundary;
|
||||
|
@ -254,7 +254,7 @@ string SMTP::boundary() {
|
|||
return boundary;
|
||||
}
|
||||
|
||||
string SMTP::filename(const string& filename) {
|
||||
auto SMTP::filename(const string& filename) -> string {
|
||||
string result;
|
||||
for(auto& n : filename) {
|
||||
if(n <= 32 || n >= 127) result.append("%", hex<2>(n));
|
||||
|
@ -263,21 +263,21 @@ string SMTP::filename(const string& filename) {
|
|||
return result;
|
||||
}
|
||||
|
||||
string SMTP::contact(const Information::Contact& contact) {
|
||||
auto SMTP::contact(const Information::Contact& contact) -> string {
|
||||
if(!contact.name) return contact.mail;
|
||||
return {"\"", contact.name, "\" <", contact.mail, ">"};
|
||||
}
|
||||
|
||||
string SMTP::contacts(const vector<Information::Contact>& contacts) {
|
||||
auto SMTP::contacts(const vector<Information::Contact>& contacts) -> string {
|
||||
string result;
|
||||
for(auto& contact : contacts) {
|
||||
result.append(this->contact(contact), "; ");
|
||||
}
|
||||
result.rtrim("; ");
|
||||
result.rtrim("; ", 1L);
|
||||
return result;
|
||||
}
|
||||
|
||||
string SMTP::split(const string& text) {
|
||||
auto SMTP::split(const string& text) -> string {
|
||||
string result;
|
||||
|
||||
unsigned offset = 0;
|
||||
|
@ -294,8 +294,8 @@ string SMTP::split(const string& text) {
|
|||
return result;
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
int SMTP::close(int sock) {
|
||||
#if defined(API_WINDOWS)
|
||||
auto SMTP::close(int sock) -> int {
|
||||
return closesocket(sock);
|
||||
}
|
||||
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
|
||||
namespace nall {
|
||||
|
||||
template<typename T, typename Comparator> void sort(T list[], unsigned size, const Comparator& lessthan) {
|
||||
template<typename T, typename Comparator> auto sort(T list[], unsigned size, const Comparator& lessthan) -> void {
|
||||
if(size <= 1) return; //nothing to sort
|
||||
|
||||
//use insertion sort to quickly sort smaller blocks
|
||||
|
@ -68,7 +68,7 @@ template<typename T, typename Comparator> void sort(T list[], unsigned size, con
|
|||
delete[] buffer;
|
||||
}
|
||||
|
||||
template<typename T> void sort(T list[], unsigned size) {
|
||||
template<typename T> auto sort(T list[], unsigned size) -> void {
|
||||
return sort(list, size, [](const T& l, const T& r) { return l < r; });
|
||||
}
|
||||
|
||||
|
|
|
@ -16,6 +16,10 @@ auto string::decimal() const -> uintmax_t {
|
|||
return nall::decimal(data());
|
||||
}
|
||||
|
||||
auto string::real() const -> double {
|
||||
return nall::real(data());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -59,13 +59,13 @@ inline auto ifindFrom(const string& self, signed offset, rstring source) -> mayb
|
|||
|
||||
//format.hpp
|
||||
template<typename... P> inline auto print(P&&...) -> void;
|
||||
template<signed precision = 0, char padchar = '0'> inline auto integer(intmax_t value) -> string;
|
||||
template<signed precision = 0, char padchar = '0'> inline auto decimal(uintmax_t value) -> string;
|
||||
template<signed precision = 0, char padchar = '0'> inline auto hex(uintmax_t value) -> string;
|
||||
template<signed precision = 0, char padchar = '0'> inline auto octal(uintmax_t value) -> string;
|
||||
template<signed precision = 0, char padchar = '0'> inline auto binary(uintmax_t value) -> string;
|
||||
template<signed precision = 0, typename T> inline auto pointer(const T* value) -> string;
|
||||
template<signed precision = 0> inline auto pointer(uintptr_t value) -> string;
|
||||
inline auto integer(intmax_t value, long precision = 0, char padchar = '0') -> string;
|
||||
inline auto decimal(uintmax_t value, long precision = 0, char padchar = '0') -> string;
|
||||
inline auto hex(uintmax_t value, long precision = 0, char padchar = '0') -> string;
|
||||
inline auto octal(uintmax_t value, long precision = 0, char padchar = '0') -> string;
|
||||
inline auto binary(uintmax_t value, long precision = 0, char padchar = '0') -> string;
|
||||
template<typename T> inline auto pointer(const T* value, long precision = 0) -> string;
|
||||
inline auto pointer(uintptr_t value, long precision = 0) -> string;
|
||||
inline auto real(long double value) -> string;
|
||||
|
||||
//hash.hpp
|
||||
|
@ -98,31 +98,31 @@ inline auto sharedpath() -> string;
|
|||
inline auto temppath() -> string;
|
||||
|
||||
//replace.hpp
|
||||
template<unsigned L, bool I, bool Q> inline auto _replace(string& self, rstring from, rstring to) -> string&;
|
||||
template<unsigned L = ~0u> inline auto replace(string& self, rstring from, rstring to) -> string&;
|
||||
template<unsigned L = ~0u> inline auto ireplace(string& self, rstring from, rstring to) -> string&;
|
||||
template<unsigned L = ~0u> inline auto qreplace(string& self, rstring from, rstring to) -> string&;
|
||||
template<unsigned L = ~0u> inline auto iqreplace(string& self, rstring from, rstring to) -> string&;
|
||||
template<bool I, bool Q> inline auto _replace(string& self, rstring from, rstring to, long limit = LONG_MAX) -> string&;
|
||||
inline auto replace(string& self, rstring from, rstring to, long limit = LONG_MAX) -> string&;
|
||||
inline auto ireplace(string& self, rstring from, rstring to, long limit = LONG_MAX) -> string&;
|
||||
inline auto qreplace(string& self, rstring from, rstring to, long limit = LONG_MAX) -> string&;
|
||||
inline auto iqreplace(string& self, rstring from, rstring to, long limit = LONG_MAX) -> string&;
|
||||
|
||||
//split.hpp
|
||||
template<unsigned L, bool I, bool Q> inline auto _split(lstring& self, rstring source, rstring find) -> lstring&;
|
||||
template<unsigned L = ~0u> inline auto split(string& self, rstring key) -> lstring;
|
||||
template<unsigned L = ~0u> inline auto isplit(string& self, rstring key) -> lstring;
|
||||
template<unsigned L = ~0u> inline auto qsplit(string& self, rstring key) -> lstring;
|
||||
template<unsigned L = ~0u> inline auto iqsplit(string& self, rstring key) -> lstring;
|
||||
template<bool I, bool Q> inline auto _split(lstring& self, rstring source, rstring find, long limit = LONG_MAX) -> lstring&;
|
||||
inline auto split(string& self, rstring key, long limit = LONG_MAX) -> lstring;
|
||||
inline auto isplit(string& self, rstring key, long limit = LONG_MAX) -> lstring;
|
||||
inline auto qsplit(string& self, rstring key, long limit = LONG_MAX) -> lstring;
|
||||
inline auto iqsplit(string& self, rstring key, long limit = LONG_MAX) -> lstring;
|
||||
|
||||
//trim.hpp
|
||||
inline auto trim(string& self, rstring lhs, rstring rhs) -> bool;
|
||||
inline auto ltrim(string& self, rstring lhs) -> bool;
|
||||
inline auto rtrim(string& self, rstring rhs) -> bool;
|
||||
inline auto trim(string& self, rstring lhs, rstring rhs, long limit = LONG_MAX) -> string&;
|
||||
inline auto ltrim(string& self, rstring lhs, long limit = LONG_MAX) -> string&;
|
||||
inline auto rtrim(string& self, rstring rhs, long limit = LONG_MAX) -> string&;
|
||||
|
||||
inline auto itrim(string& self, rstring lhs, rstring rhs) -> bool;
|
||||
inline auto iltrim(string& self, rstring lhs) -> bool;
|
||||
inline auto irtrim(string& self, rstring rhs) -> bool;
|
||||
inline auto itrim(string& self, rstring lhs, rstring rhs, long limit = LONG_MAX) -> string&;
|
||||
inline auto iltrim(string& self, rstring lhs, long limit = LONG_MAX) -> string&;
|
||||
inline auto irtrim(string& self, rstring rhs, long limit = LONG_MAX) -> string&;
|
||||
|
||||
inline auto strip(string& self) -> bool;
|
||||
inline auto lstrip(string& self) -> bool;
|
||||
inline auto rstrip(string& self) -> bool;
|
||||
inline auto strip(string& self) -> string&;
|
||||
inline auto lstrip(string& self) -> string&;
|
||||
inline auto rstrip(string& self) -> string&;
|
||||
|
||||
//utility.hpp
|
||||
inline auto fill(string& self, char fill = ' ') -> string&;
|
||||
|
@ -190,7 +190,7 @@ public:
|
|||
inline auto operator=(const string&) -> type&;
|
||||
inline auto operator=(string&&) -> type&;
|
||||
|
||||
template<typename T, typename... P> string(T&& s, P&&... p) : string() { append(std::forward<T>(s), std::forward<P>(p)...); }
|
||||
template<typename T, typename... P> string(T&& s, P&&... p) : string() { append(forward<T>(s), forward<P>(p)...); }
|
||||
~string() { reset(); }
|
||||
|
||||
explicit operator bool() const { return _size; }
|
||||
|
@ -222,6 +222,7 @@ public:
|
|||
//atoi.hpp
|
||||
inline auto integer() const -> intmax_t;
|
||||
inline auto decimal() const -> uintmax_t;
|
||||
inline auto real() const -> double;
|
||||
|
||||
//core.hpp
|
||||
inline auto operator[](signed) const -> const char&;
|
||||
|
@ -236,7 +237,7 @@ public:
|
|||
|
||||
//utility.hpp
|
||||
inline static auto read(const string& filename) -> string;
|
||||
template<unsigned L> inline static auto repeat(const string& pattern) -> string;
|
||||
inline static auto repeat(const string& pattern, unsigned times) -> string;
|
||||
|
||||
//extension methods
|
||||
//=================
|
||||
|
@ -264,8 +265,8 @@ public:
|
|||
auto transform(rstring from, rstring to) -> type& { return nall::transform(*this, from, to); }
|
||||
|
||||
//core.hpp
|
||||
template<typename... P> auto assign(P&&... p) -> type& { return nall::assign(*this, std::forward<P>(p)...); }
|
||||
template<typename... P> auto append(P&&... p) -> type& { return nall::append(*this, std::forward<P>(p)...); }
|
||||
template<typename... P> auto assign(P&&... p) -> type& { return nall::assign(*this, forward<P>(p)...); }
|
||||
template<typename... P> auto append(P&&... p) -> type& { return nall::append(*this, forward<P>(p)...); }
|
||||
auto empty() const -> bool { return nall::empty(*this); }
|
||||
auto length() const -> unsigned { return nall::length(*this); }
|
||||
|
||||
|
@ -297,29 +298,29 @@ public:
|
|||
auto suffixname() const -> string { return nall::suffixname(*this); }
|
||||
|
||||
//replace.hpp
|
||||
template<unsigned L = ~0u> auto replace(rstring from, rstring to) -> type& { return nall::_replace<L, 0, 0>(*this, from, to); }
|
||||
template<unsigned L = ~0u> auto ireplace(rstring from, rstring to) -> type& { return nall::_replace<L, 1, 0>(*this, from, to); }
|
||||
template<unsigned L = ~0u> auto qreplace(rstring from, rstring to) -> type& { return nall::_replace<L, 0, 1>(*this, from, to); }
|
||||
template<unsigned L = ~0u> auto iqreplace(rstring from, rstring to) -> type& { return nall::_replace<L, 1, 1>(*this, from, to); }
|
||||
auto replace(rstring from, rstring to, long limit = LONG_MAX) -> type& { return nall::_replace<0, 0>(*this, from, to, limit); }
|
||||
auto ireplace(rstring from, rstring to, long limit = LONG_MAX) -> type& { return nall::_replace<1, 0>(*this, from, to, limit); }
|
||||
auto qreplace(rstring from, rstring to, long limit = LONG_MAX) -> type& { return nall::_replace<0, 1>(*this, from, to, limit); }
|
||||
auto iqreplace(rstring from, rstring to, long limit = LONG_MAX) -> type& { return nall::_replace<1, 1>(*this, from, to, limit); }
|
||||
|
||||
//split.hpp
|
||||
template<unsigned L = ~0u> inline auto split(rstring key) const -> lstring;
|
||||
template<unsigned L = ~0u> inline auto isplit(rstring key) const -> lstring;
|
||||
template<unsigned L = ~0u> inline auto qsplit(rstring key) const -> lstring;
|
||||
template<unsigned L = ~0u> inline auto iqsplit(rstring key) const -> lstring;
|
||||
inline auto split(rstring key, long limit = LONG_MAX) const -> lstring;
|
||||
inline auto isplit(rstring key, long limit = LONG_MAX) const -> lstring;
|
||||
inline auto qsplit(rstring key, long limit = LONG_MAX) const -> lstring;
|
||||
inline auto iqsplit(rstring key, long limit = LONG_MAX) const -> lstring;
|
||||
|
||||
//trim.hpp
|
||||
auto trim(rstring lhs, rstring rhs) -> type& { return nall::trim(*this, lhs, rhs), *this; }
|
||||
auto ltrim(rstring lhs) -> type& { return nall::ltrim(*this, lhs), *this; }
|
||||
auto rtrim(rstring rhs) -> type& { return nall::rtrim(*this, rhs), *this; }
|
||||
auto trim(rstring lhs, rstring rhs, long limit = LONG_MAX) -> type& { return nall::trim(*this, lhs, rhs, limit); }
|
||||
auto ltrim(rstring lhs, long limit = LONG_MAX) -> type& { return nall::ltrim(*this, lhs, limit); }
|
||||
auto rtrim(rstring rhs, long limit = LONG_MAX) -> type& { return nall::rtrim(*this, rhs, limit); }
|
||||
|
||||
auto itrim(rstring lhs, rstring rhs) -> type& { return nall::itrim(*this, lhs, rhs), *this; }
|
||||
auto iltrim(rstring lhs) -> type& { return nall::iltrim(*this, lhs), *this; }
|
||||
auto irtrim(rstring rhs) -> type& { return nall::irtrim(*this, rhs), *this; }
|
||||
auto itrim(rstring lhs, rstring rhs, long limit = LONG_MAX) -> type& { return nall::itrim(*this, lhs, rhs, limit); }
|
||||
auto iltrim(rstring lhs, long limit = LONG_MAX) -> type& { return nall::iltrim(*this, lhs, limit); }
|
||||
auto irtrim(rstring rhs, long limit = LONG_MAX) -> type& { return nall::irtrim(*this, rhs, limit); }
|
||||
|
||||
auto strip() -> type& { return nall::strip(*this), *this; }
|
||||
auto lstrip() -> type& { return nall::lstrip(*this), *this; }
|
||||
auto rstrip() -> type& { return nall::rstrip(*this), *this; }
|
||||
auto strip() -> type& { return nall::strip(*this); }
|
||||
auto lstrip() -> type& { return nall::lstrip(*this); }
|
||||
auto rstrip() -> type& { return nall::rstrip(*this); }
|
||||
|
||||
//utility.hpp
|
||||
auto fill(char fill = ' ') -> type& { return nall::fill(*this, fill); }
|
||||
|
@ -348,7 +349,7 @@ struct lstring : vector<string> {
|
|||
lstring(const lstring& source) { vector::operator=(source); }
|
||||
lstring(lstring& source) { vector::operator=(source); }
|
||||
lstring(lstring&& source) { vector::operator=(std::move(source)); }
|
||||
template<typename... P> lstring(P&&... p) { append(std::forward<P>(p)...); }
|
||||
template<typename... P> lstring(P&&... p) { append(forward<P>(p)...); }
|
||||
|
||||
//list.hpp
|
||||
inline auto operator==(const lstring&) const -> bool;
|
||||
|
@ -364,17 +365,17 @@ struct lstring : vector<string> {
|
|||
//=================
|
||||
|
||||
//list.hpp
|
||||
template<typename... P> auto append(P&&... p) -> type& { return nall::append(*this, std::forward<P>(p)...); }
|
||||
template<typename... P> auto append(P&&... p) -> type& { return nall::append(*this, forward<P>(p)...); }
|
||||
auto find(const string& source) const -> maybe<unsigned> { return nall::find(*this, source); }
|
||||
auto ifind(const string& source) const -> maybe<unsigned> { return nall::ifind(*this, source); }
|
||||
auto merge(const string& separator) const -> string { return nall::merge(*this, separator); }
|
||||
auto strip() -> type& { return nall::strip(*this); }
|
||||
|
||||
//split.hpp
|
||||
template<unsigned L = ~0u> auto split(rstring source, rstring on) -> type& { return nall::_split<L, 0, 0>(*this, source, on); }
|
||||
template<unsigned L = ~0u> auto isplit(rstring source, rstring on) -> type& { return nall::_split<L, 1, 0>(*this, source, on); }
|
||||
template<unsigned L = ~0u> auto qsplit(rstring source, rstring on) -> type& { return nall::_split<L, 0, 1>(*this, source, on); }
|
||||
template<unsigned L = ~0u> auto iqsplit(rstring source, rstring on) -> type& { return nall::_split<L, 1, 1>(*this, source, on); }
|
||||
auto split(rstring source, rstring on, long limit = LONG_MAX) -> type& { return nall::_split<0, 0>(*this, source, on, limit); }
|
||||
auto isplit(rstring source, rstring on, long limit = LONG_MAX) -> type& { return nall::_split<1, 0>(*this, source, on, limit); }
|
||||
auto qsplit(rstring source, rstring on, long limit = LONG_MAX) -> type& { return nall::_split<0, 1>(*this, source, on, limit); }
|
||||
auto iqsplit(rstring source, rstring on, long limit = LONG_MAX) -> type& { return nall::_split<1, 1>(*this, source, on, limit); }
|
||||
};
|
||||
|
||||
//format.hpp
|
||||
|
@ -384,8 +385,8 @@ inline auto append(format& self) -> format&;
|
|||
struct format : vector<string> {
|
||||
using type = format;
|
||||
|
||||
template<typename... P> format(P&&... p) { reserve(sizeof...(p)); append(std::forward<P>(p)...); }
|
||||
template<typename... P> auto append(P&&... p) -> type& { return nall::append(*this, std::forward<P>(p)...); }
|
||||
template<typename... P> format(P&&... p) { reserve(sizeof...(p)); append(forward<P>(p)...); }
|
||||
template<typename... P> auto append(P&&... p) -> type& { return nall::append(*this, forward<P>(p)...); }
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -6,9 +6,9 @@ auto string::date(time_t timestamp) -> string {
|
|||
if(timestamp == 0) timestamp = ::time(nullptr);
|
||||
tm* info = localtime(×tamp);
|
||||
return {
|
||||
nall::decimal<4>(1900 + info->tm_year), "-",
|
||||
nall::decimal<2>(1 + info->tm_mon), "-",
|
||||
nall::decimal<2>(info->tm_mday)
|
||||
nall::decimal(1900 + info->tm_year, 4L), "-",
|
||||
nall::decimal(1 + info->tm_mon, 2L), "-",
|
||||
nall::decimal(info->tm_mday, 2L)
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -16,9 +16,9 @@ auto string::time(time_t timestamp) -> string {
|
|||
if(timestamp == 0) timestamp = ::time(nullptr);
|
||||
tm* info = localtime(×tamp);
|
||||
return {
|
||||
nall::decimal<2>(info->tm_hour), ":",
|
||||
nall::decimal<2>(info->tm_min), ":",
|
||||
nall::decimal<2>(info->tm_sec)
|
||||
nall::decimal(info->tm_hour, 2L), ":",
|
||||
nall::decimal(info->tm_min, 2L), ":",
|
||||
nall::decimal(info->tm_sec, 2L)
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -29,7 +29,7 @@ inline string evaluateExpression(Node* node) {
|
|||
for(auto& link : node->link) {
|
||||
result.append(evaluateExpression(link), ", ");
|
||||
}
|
||||
return result.rtrim(", ").append(")");
|
||||
return result.rtrim(", ", 1L).append(")");
|
||||
}
|
||||
}
|
||||
#undef p
|
||||
|
|
|
@ -73,7 +73,7 @@ template<typename... P> auto print(P&&... p) -> void {
|
|||
fputs(s.data(), stdout);
|
||||
}
|
||||
|
||||
template<signed precision, char padchar> auto integer(intmax_t value) -> string {
|
||||
auto integer(intmax_t value, long precision, char padchar) -> string {
|
||||
string buffer;
|
||||
buffer.resize(1 + sizeof(intmax_t) * 3);
|
||||
char* p = buffer.pointer();
|
||||
|
@ -92,7 +92,7 @@ template<signed precision, char padchar> auto integer(intmax_t value) -> string
|
|||
return buffer;
|
||||
}
|
||||
|
||||
template<signed precision, char padchar> auto decimal(uintmax_t value) -> string {
|
||||
auto decimal(uintmax_t value, long precision, char padchar) -> string {
|
||||
string buffer;
|
||||
buffer.resize(sizeof(uintmax_t) * 3);
|
||||
char* p = buffer.pointer();
|
||||
|
@ -108,7 +108,7 @@ template<signed precision, char padchar> auto decimal(uintmax_t value) -> string
|
|||
return buffer;
|
||||
}
|
||||
|
||||
template<signed precision, char padchar> auto hex(uintmax_t value) -> string {
|
||||
auto hex(uintmax_t value, long precision, char padchar) -> string {
|
||||
string buffer;
|
||||
buffer.resize(sizeof(uintmax_t) * 2);
|
||||
char* p = buffer.pointer();
|
||||
|
@ -125,7 +125,7 @@ template<signed precision, char padchar> auto hex(uintmax_t value) -> string {
|
|||
return buffer;
|
||||
}
|
||||
|
||||
template<signed precision, char padchar> auto octal(uintmax_t value) -> string {
|
||||
auto octal(uintmax_t value, long precision, char padchar) -> string {
|
||||
string buffer;
|
||||
buffer.resize(sizeof(uintmax_t) * 3);
|
||||
char* p = buffer.pointer();
|
||||
|
@ -141,7 +141,7 @@ template<signed precision, char padchar> auto octal(uintmax_t value) -> string {
|
|||
return buffer;
|
||||
}
|
||||
|
||||
template<signed precision, char padchar> auto binary(uintmax_t value) -> string {
|
||||
auto binary(uintmax_t value, long precision, char padchar) -> string {
|
||||
string buffer;
|
||||
buffer.resize(sizeof(uintmax_t) * 8);
|
||||
char* p = buffer.pointer();
|
||||
|
@ -157,14 +157,14 @@ template<signed precision, char padchar> auto binary(uintmax_t value) -> string
|
|||
return buffer;
|
||||
}
|
||||
|
||||
template<signed precision, typename T> auto pointer(const T* value) -> string {
|
||||
template<typename T> auto pointer(const T* value, long precision) -> string {
|
||||
if(value == nullptr) return "(null)";
|
||||
return {"0x", hex<precision>((uintptr_t)value)};
|
||||
return {"0x", hex((uintptr_t)value, precision)};
|
||||
}
|
||||
|
||||
template<signed precision> auto pointer(uintptr_t value) -> string {
|
||||
auto pointer(uintptr_t value, long precision) -> string {
|
||||
if(value == 0) return "(null)";
|
||||
return {"0x", hex<precision>(value)};
|
||||
return {"0x", hex(value, precision)};
|
||||
}
|
||||
|
||||
auto real(long double value) -> string {
|
||||
|
|
|
@ -4,16 +4,16 @@ namespace nall {
|
|||
|
||||
namespace Hash {
|
||||
auto CRC16::digest() -> string {
|
||||
return hex<4>(value());
|
||||
return hex(value(), 4L);
|
||||
}
|
||||
|
||||
auto CRC32::digest() -> string {
|
||||
return hex<8>(value());
|
||||
return hex(value(), 8L);
|
||||
}
|
||||
|
||||
auto SHA256::digest() const -> string {
|
||||
string result;
|
||||
for(auto n : value()) result.append(hex<2>(n));
|
||||
for(auto n : value()) result.append(hex(n, 2L));
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -75,7 +75,7 @@ protected:
|
|||
if(length == 0) throw "Invalid attribute name";
|
||||
node->_name = substr(p, 0, length);
|
||||
node->parseData(p += length);
|
||||
node->_value.rtrim("\n");
|
||||
node->_value.rtrim("\n", 1L);
|
||||
_children.append(node);
|
||||
}
|
||||
}
|
||||
|
@ -102,7 +102,7 @@ protected:
|
|||
_children.append(node);
|
||||
}
|
||||
|
||||
_value.rtrim("\n");
|
||||
_value.rtrim("\n", 1L);
|
||||
}
|
||||
|
||||
//read top-level nodes
|
||||
|
|
|
@ -23,12 +23,12 @@ auto ManagedNode::_evaluate(string query) const -> bool {
|
|||
|
||||
lstring side;
|
||||
switch(comparator) {
|
||||
case Comparator::EQ: side = rule.split<1> ("="); break;
|
||||
case Comparator::NE: side = rule.split<1>("!="); break;
|
||||
case Comparator::LT: side = rule.split<1> ("<"); break;
|
||||
case Comparator::LE: side = rule.split<1>("<="); break;
|
||||
case Comparator::GT: side = rule.split<1> (">"); break;
|
||||
case Comparator::GE: side = rule.split<1>(">="); break;
|
||||
case Comparator::EQ: side = rule.split ("=", 1L); break;
|
||||
case Comparator::NE: side = rule.split("!=", 1L); break;
|
||||
case Comparator::LT: side = rule.split ("<", 1L); break;
|
||||
case Comparator::LE: side = rule.split("<=", 1L); break;
|
||||
case Comparator::GT: side = rule.split (">", 1L); break;
|
||||
case Comparator::GE: side = rule.split(">=", 1L); break;
|
||||
}
|
||||
|
||||
string data = string{_value}.strip();
|
||||
|
@ -61,10 +61,10 @@ auto ManagedNode::_find(const string& query) const -> vector<Node> {
|
|||
unsigned lo = 0u, hi = ~0u;
|
||||
|
||||
if(name.match("*[*]")) {
|
||||
auto p = name.rtrim("]").split<1>("[");
|
||||
auto p = name.rtrim("]", 1L).split("[", 1L);
|
||||
name = p(0);
|
||||
if(p(1).find("-")) {
|
||||
p = p(1).split<1>("-");
|
||||
p = p(1).split("-", 1L);
|
||||
lo = p(0).empty() ? 0u : p(0).decimal();
|
||||
hi = p(1).empty() ? ~0u : p(1).decimal();
|
||||
} else {
|
||||
|
@ -73,7 +73,7 @@ auto ManagedNode::_find(const string& query) const -> vector<Node> {
|
|||
}
|
||||
|
||||
if(name.match("*(*)")) {
|
||||
auto p = name.rtrim(")").split<1>("(");
|
||||
auto p = name.rtrim(")", 1L).split("(", 1L);
|
||||
name = p(0);
|
||||
rule = p(1);
|
||||
}
|
||||
|
|
|
@ -2,9 +2,9 @@
|
|||
|
||||
namespace nall {
|
||||
|
||||
template<unsigned Limit, bool Insensitive, bool Quoted>
|
||||
auto _replace(string& self, rstring from, rstring to) -> string& {
|
||||
if(Limit == 0 || from.size() == 0) return self;
|
||||
template<bool Insensitive, bool Quoted>
|
||||
auto _replace(string& self, rstring from, rstring to, long limit) -> string& {
|
||||
if(limit <= 0 || from.size() == 0) return self;
|
||||
|
||||
signed size = self.size();
|
||||
signed matches = 0;
|
||||
|
@ -17,7 +17,7 @@ auto _replace(string& self, rstring from, rstring to) -> string& {
|
|||
if(Quoted) { if(p[n] == '\"') { quoted ^= 1; n++; continue; } if(quoted) { n++; continue; } }
|
||||
if(_compare<Insensitive>(p + n, size - n, from.data(), from.size())) { n++; continue; }
|
||||
|
||||
if(++matches >= Limit) break;
|
||||
if(++matches >= limit) break;
|
||||
n += from.size();
|
||||
}
|
||||
}
|
||||
|
@ -86,10 +86,10 @@ auto _replace(string& self, rstring from, rstring to) -> string& {
|
|||
return self;
|
||||
}
|
||||
|
||||
template<unsigned L> auto replace(string& self, rstring from, rstring to) -> string& { return _replace<L, 0, 0>(self, from, to); }
|
||||
template<unsigned L> auto ireplace(string& self, rstring from, rstring to) -> string& { return _replace<L, 1, 0>(self, from, to); }
|
||||
template<unsigned L> auto qreplace(string& self, rstring from, rstring to) -> string& { return _replace<L, 0, 1>(self, from, to); }
|
||||
template<unsigned L> auto iqreplace(string& self, rstring from, rstring to) -> string& { return _replace<L, 1, 1>(self, from, to); }
|
||||
auto replace(string& self, rstring from, rstring to, long limit) -> string& { return _replace<0, 0>(self, from, to, limit); }
|
||||
auto ireplace(string& self, rstring from, rstring to, long limit) -> string& { return _replace<1, 0>(self, from, to, limit); }
|
||||
auto qreplace(string& self, rstring from, rstring to, long limit) -> string& { return _replace<0, 1>(self, from, to, limit); }
|
||||
auto iqreplace(string& self, rstring from, rstring to, long limit) -> string& { return _replace<1, 1>(self, from, to, limit); }
|
||||
|
||||
};
|
||||
|
||||
|
|
|
@ -2,9 +2,9 @@
|
|||
|
||||
namespace nall {
|
||||
|
||||
template<unsigned Limit, bool Insensitive, bool Quoted> auto _split(lstring& self, rstring source, rstring find) -> lstring& {
|
||||
template<bool Insensitive, bool Quoted> auto _split(lstring& self, rstring source, rstring find, long limit) -> lstring& {
|
||||
self.reset();
|
||||
if(find.size() == 0) return self;
|
||||
if(limit <= 0 || find.size() == 0) return self;
|
||||
|
||||
const char* p = source.data();
|
||||
signed size = source.size();
|
||||
|
@ -14,7 +14,7 @@ template<unsigned Limit, bool Insensitive, bool Quoted> auto _split(lstring& sel
|
|||
for(signed n = 0, quoted = 0; n <= size - (signed)find.size();) {
|
||||
if(Quoted) { if(p[n] == '\"') { quoted ^= 1; n++; continue; } if(quoted) { n++; continue; } }
|
||||
if(_compare<Insensitive>(p + n, size - n, find.data(), find.size())) { n++; continue; }
|
||||
if(matches >= Limit) break;
|
||||
if(matches >= limit) break;
|
||||
|
||||
string& s = self(matches);
|
||||
s.resize(n - base);
|
||||
|
@ -32,15 +32,15 @@ template<unsigned Limit, bool Insensitive, bool Quoted> auto _split(lstring& sel
|
|||
return self;
|
||||
}
|
||||
|
||||
template<unsigned L> auto split(string& self, rstring on) -> lstring { return lstring().split<L>(self, on); }
|
||||
template<unsigned L> auto isplit(string& self, rstring on) -> lstring { return lstring().isplit<L>(self, on); }
|
||||
template<unsigned L> auto qsplit(string& self, rstring on) -> lstring { return lstring().qsplit<L>(self, on); }
|
||||
template<unsigned L> auto iqsplit(string& self, rstring on) -> lstring { return lstring().iqsplit<L>(self, on); }
|
||||
auto split(string& self, rstring on, long limit) -> lstring { return lstring().split(self, on, limit); }
|
||||
auto isplit(string& self, rstring on, long limit) -> lstring { return lstring().isplit(self, on, limit); }
|
||||
auto qsplit(string& self, rstring on, long limit) -> lstring { return lstring().qsplit(self, on, limit); }
|
||||
auto iqsplit(string& self, rstring on, long limit) -> lstring { return lstring().iqsplit(self, on, limit); }
|
||||
|
||||
template<unsigned L> auto string::split(rstring on) const -> lstring { return lstring().split<L>(*this, on); }
|
||||
template<unsigned L> auto string::isplit(rstring on) const -> lstring { return lstring().isplit<L>(*this, on); }
|
||||
template<unsigned L> auto string::qsplit(rstring on) const -> lstring { return lstring().qsplit<L>(*this, on); }
|
||||
template<unsigned L> auto string::iqsplit(rstring on) const -> lstring { return lstring().iqsplit<L>(*this, on); }
|
||||
auto string::split(rstring on, long limit) const -> lstring { return lstring().split(*this, on, limit); }
|
||||
auto string::isplit(rstring on, long limit) const -> lstring { return lstring().isplit(*this, on, limit); }
|
||||
auto string::qsplit(rstring on, long limit) const -> lstring { return lstring().qsplit(*this, on, limit); }
|
||||
auto string::iqsplit(rstring on, long limit) const -> lstring { return lstring().iqsplit(*this, on, limit); }
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -1,17 +1,24 @@
|
|||
#ifdef NALL_STRING_INTERNAL_HPP
|
||||
|
||||
/* CSS Markup Language (CML) v1.0 parser
|
||||
* revision 0.01
|
||||
* revision 0.02
|
||||
*/
|
||||
|
||||
namespace nall { namespace {
|
||||
|
||||
struct CML {
|
||||
CML(const string& filedata, const string& pathname);
|
||||
CML(const string& filename);
|
||||
auto output() -> string;
|
||||
auto& setPath(const string& pathname) { settings.path = pathname; return *this; }
|
||||
auto& setReader(const function<string (string)>& reader) { settings.reader = reader; return *this; }
|
||||
|
||||
auto parse(const string& filename) -> string;
|
||||
auto parse(const string& filedata, const string& pathname) -> string;
|
||||
|
||||
private:
|
||||
struct Settings {
|
||||
string path;
|
||||
function<string (string)> reader;
|
||||
} settings;
|
||||
|
||||
struct State {
|
||||
string output;
|
||||
} state;
|
||||
|
@ -22,22 +29,25 @@ private:
|
|||
};
|
||||
vector<Variable> variables;
|
||||
|
||||
auto parse(const string& filedata, const string& pathname) -> bool;
|
||||
auto parseDocument(const string& filedata, const string& pathname, unsigned depth) -> bool;
|
||||
};
|
||||
|
||||
CML::CML(const string& filedata, const string& pathname) {
|
||||
parse(filedata, pathname);
|
||||
}
|
||||
|
||||
CML::CML(const string& filename) {
|
||||
parse(string::read(filename), filename.pathname());
|
||||
}
|
||||
|
||||
auto CML::output() -> string {
|
||||
auto CML::parse(const string& filename) -> string {
|
||||
if(!settings.path) settings.path = filename.pathname();
|
||||
string document = settings.reader ? settings.reader(filename) : string::read(filename);
|
||||
parseDocument(document, settings.path, 0);
|
||||
return state.output;
|
||||
}
|
||||
|
||||
auto CML::parse(const string& filedata, const string& pathname) -> bool {
|
||||
auto CML::parse(const string& filedata, const string& pathname) -> string {
|
||||
settings.path = pathname;
|
||||
parseDocument(filedata, settings.path, 0);
|
||||
return state.output;
|
||||
}
|
||||
|
||||
auto CML::parseDocument(const string& filedata, const string& pathname, unsigned depth) -> bool {
|
||||
if(depth >= 100) return false; //prevent infinite recursion
|
||||
|
||||
auto vendorAppend = [&](const string& name, const string& value) {
|
||||
state.output.append(" -moz-", name, ": ", value, ";\n");
|
||||
state.output.append(" -webkit-", name, ": ", value, ";\n");
|
||||
|
@ -47,15 +57,17 @@ auto CML::parse(const string& filedata, const string& pathname) -> bool {
|
|||
lstring lines = block.rstrip().split("\n");
|
||||
string name = lines.takeFirst();
|
||||
|
||||
if(ltrim(name, "include ")) {
|
||||
if(name.beginsWith("include ")) {
|
||||
name.ltrim("include ", 1L);
|
||||
string filename{pathname, name};
|
||||
parse(string::read(filename), filename.pathname());
|
||||
string document = settings.reader ? settings.reader(filename) : string::read(filename);
|
||||
parseDocument(document, filename.pathname(), depth + 1);
|
||||
continue;
|
||||
}
|
||||
|
||||
if(name == "variables") {
|
||||
for(auto& line : lines) {
|
||||
auto data = line.split<1>(":").strip();
|
||||
auto data = line.split(":", 1L).strip();
|
||||
variables.append({data(0), data(1)});
|
||||
}
|
||||
continue;
|
||||
|
@ -63,7 +75,7 @@ auto CML::parse(const string& filedata, const string& pathname) -> bool {
|
|||
|
||||
state.output.append(name, " {\n");
|
||||
for(auto& line : lines) {
|
||||
auto data = line.split<1>(":").strip();
|
||||
auto data = line.split(":", 1L).strip();
|
||||
auto name = data(0), value = data(1);
|
||||
while(auto offset = value.find("var(")) {
|
||||
bool found = false;
|
||||
|
|
|
@ -1,92 +1,104 @@
|
|||
#ifdef NALL_STRING_INTERNAL_HPP
|
||||
|
||||
/* Document Markup Language (DML) v1.0 parser
|
||||
* revision 0.01
|
||||
* revision 0.03
|
||||
*/
|
||||
|
||||
namespace nall { namespace {
|
||||
|
||||
struct DML {
|
||||
auto& setAllowHTML(bool allowHTML) { settings.allowHTML = allowHTML; return *this; }
|
||||
auto& setHost(const string& hostname) { settings.host = {hostname, "/"}; return *this; }
|
||||
auto& setPath(const string& pathname) { settings.path = pathname; return *this; }
|
||||
auto& setReader(const function<string (string)>& reader) { settings.reader = reader; return *this; }
|
||||
auto& setSectioned(bool sectioned) { settings.sectioned = sectioned; return *this; }
|
||||
|
||||
auto parse(const string& filedata, const string& pathname) -> string;
|
||||
auto parse(const string& filename) -> string;
|
||||
|
||||
private:
|
||||
struct Settings {
|
||||
bool allowHTML = true;
|
||||
string host = "localhost/";
|
||||
string path;
|
||||
function<string (string)> reader;
|
||||
bool sectioned = true;
|
||||
} settings;
|
||||
|
||||
DML(const string& filedata, const string& pathname);
|
||||
DML(const string& filename);
|
||||
auto output() -> string;
|
||||
|
||||
private:
|
||||
struct State {
|
||||
string output;
|
||||
unsigned sections = 0;
|
||||
} state;
|
||||
|
||||
auto parse(const string& filedata, const string& pathname) -> bool;
|
||||
auto parseBlock(string& block, const string& pathname) -> bool;
|
||||
auto parseDocument(const string& filedata, const string& pathname, unsigned depth) -> bool;
|
||||
auto parseBlock(string& block, const string& pathname, unsigned depth) -> bool;
|
||||
auto count(const string& text, char value) -> unsigned;
|
||||
|
||||
auto escape(const string& text) -> string;
|
||||
auto markup(const string& text) -> string;
|
||||
};
|
||||
|
||||
DML::DML(const string& filedata, const string& pathname) {
|
||||
parse(filedata, pathname);
|
||||
}
|
||||
|
||||
DML::DML(const string& filename) {
|
||||
parse(string::read(filename), filename.pathname());
|
||||
}
|
||||
|
||||
auto DML::output() -> string {
|
||||
auto DML::parse(const string& filedata, const string& pathname) -> string {
|
||||
settings.path = pathname;
|
||||
parseDocument(filedata, settings.path, 0);
|
||||
return state.output;
|
||||
}
|
||||
|
||||
auto DML::parse(const string& filedata, const string& pathname) -> bool {
|
||||
auto DML::parse(const string& filename) -> string {
|
||||
if(!settings.path) settings.path = filename.pathname();
|
||||
string document = settings.reader ? settings.reader(filename) : string::read(filename);
|
||||
parseDocument(document, settings.path, 0);
|
||||
return state.output;
|
||||
}
|
||||
|
||||
auto DML::parseDocument(const string& filedata, const string& pathname, unsigned depth) -> bool {
|
||||
if(depth >= 100) return false; //attempt to prevent infinite recursion with reasonable limit
|
||||
|
||||
auto blocks = filedata.split("\n\n");
|
||||
for(auto& block : blocks) parseBlock(block, pathname);
|
||||
if(settings.sectioned && state.sections) state.output.append("</section>\n");
|
||||
for(auto& block : blocks) parseBlock(block, pathname, depth);
|
||||
if(settings.sectioned && state.sections && depth == 0) state.output.append("</section>\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
auto DML::parseBlock(string& block, const string& pathname) -> bool {
|
||||
auto DML::parseBlock(string& block, const string& pathname, unsigned depth) -> bool {
|
||||
if(block.rstrip().empty()) return true;
|
||||
auto lines = block.split("\n");
|
||||
|
||||
//include
|
||||
if(block.beginsWith("{{include}}")) {
|
||||
string filename{pathname, block.ltrim("{{include}}").strip()};
|
||||
parse(string::read(filename), filename.pathname());
|
||||
if(block.beginsWith("<include ") && block.endsWith(">")) {
|
||||
string filename{pathname, block.trim("<include ", ">", 1L).strip()};
|
||||
string document = settings.reader ? settings.reader(filename) : string::read(filename);
|
||||
parseDocument(document, filename.pathname(), depth + 1);
|
||||
}
|
||||
|
||||
//html
|
||||
else if(ltrim(block, "{{html}}") && settings.allowHTML) {
|
||||
auto data = lines.takeFirst();
|
||||
if(ltrim(data, "{{html}} ")) state.output.append(data, "\n");
|
||||
for(auto& line : lines) {
|
||||
if(ltrim(line, " ")) state.output.append(line, "\n");
|
||||
else if(block.beginsWith("<html>\n") && settings.allowHTML) {
|
||||
for(auto n : range(lines)) {
|
||||
if(n == 0 || !lines[n].beginsWith(" ")) continue;
|
||||
state.output.append(lines[n].ltrim(" ", 1L), "\n");
|
||||
}
|
||||
}
|
||||
|
||||
//header
|
||||
//section
|
||||
else if(block.beginsWith("# ")) {
|
||||
if(settings.sectioned) {
|
||||
if(state.sections++) state.output.append("</section>");
|
||||
state.output.append("<section>");
|
||||
}
|
||||
auto content = lines.takeFirst().ltrim("# ").split<1>(" => ");
|
||||
auto content = lines.takeFirst().ltrim("# ", 1L).split(" => ", 1L);
|
||||
auto data = markup(content[0]);
|
||||
auto name = escape(content(1, data.crc32()));
|
||||
state.output.append("<header id=\"", name, "\">", data);
|
||||
for(auto& line : lines) {
|
||||
if(!line.beginsWith("# ")) continue;
|
||||
state.output.append("<span>", line.ltrim("# "), "</span>");
|
||||
state.output.append("<span>", line.ltrim("# ", 1L), "</span>");
|
||||
}
|
||||
state.output.append("</header>\n");
|
||||
}
|
||||
|
||||
//subheader
|
||||
//header
|
||||
else if(auto depth = count(block, '=')) {
|
||||
auto content = lines.takeFirst().slice(depth + 1).split<1>(" => ");
|
||||
auto content = lines.takeFirst().slice(depth + 1).split(" => ", 1L);
|
||||
auto data = markup(content[0]);
|
||||
auto name = escape(content(1, data.crc32()));
|
||||
if(depth <= 6) {
|
||||
|
@ -99,7 +111,7 @@ auto DML::parseBlock(string& block, const string& pathname) -> bool {
|
|||
}
|
||||
}
|
||||
|
||||
//contents
|
||||
//navigation
|
||||
else if(count(block, '-')) {
|
||||
state.output.append("<nav>\n");
|
||||
unsigned level = 0;
|
||||
|
@ -107,7 +119,7 @@ auto DML::parseBlock(string& block, const string& pathname) -> bool {
|
|||
if(auto depth = count(line, '-')) {
|
||||
while(level < depth) level++, state.output.append("<ul>\n");
|
||||
while(level > depth) level--, state.output.append("</ul>\n");
|
||||
auto content = line.slice(depth + 1).split<1>(" => ");
|
||||
auto content = line.slice(depth + 1).split(" => ", 1L);
|
||||
auto data = markup(content[0]);
|
||||
auto name = escape(content(1, data.crc32()));
|
||||
state.output.append("<li><a href=\"#", name, "\">", data, "</a></li>\n");
|
||||
|
@ -149,10 +161,10 @@ auto DML::parseBlock(string& block, const string& pathname) -> bool {
|
|||
else if(block.beginsWith(" ")) {
|
||||
state.output.append("<pre>");
|
||||
for(auto& line : lines) {
|
||||
if(!ltrim(line, " ")) continue;
|
||||
state.output.append(escape(line), "\n");
|
||||
if(!line.beginsWith(" ")) continue;
|
||||
state.output.append(escape(line.ltrim(" ", 1L)), "\n");
|
||||
}
|
||||
state.output.rtrim("\n").append("</pre>\n");
|
||||
state.output.rtrim("\n", 1L).append("</pre>\n");
|
||||
}
|
||||
|
||||
//divider
|
||||
|
@ -180,77 +192,75 @@ auto DML::count(const string& text, char value) -> unsigned {
|
|||
|
||||
auto DML::escape(const string& text) -> string {
|
||||
string output;
|
||||
for(unsigned n = 0; n < text.size();) {
|
||||
char x = text[n++];
|
||||
if(x == '&') { output.append("&"); continue; }
|
||||
if(x == '<') { output.append("<"); continue; }
|
||||
if(x == '>') { output.append(">"); continue; }
|
||||
if(x == '"') { output.append("""); continue; }
|
||||
output.append(x);
|
||||
for(auto c : text) {
|
||||
if(c == '&') { output.append("&"); continue; }
|
||||
if(c == '<') { output.append("<"); continue; }
|
||||
if(c == '>') { output.append(">"); continue; }
|
||||
if(c == '"') { output.append("""); continue; }
|
||||
output.append(c);
|
||||
}
|
||||
return output;
|
||||
}
|
||||
|
||||
auto DML::markup(const string& text) -> string {
|
||||
string output;
|
||||
char flagStrong = 0;
|
||||
char flagEmphasis = 0;
|
||||
char flagInsert = 0;
|
||||
char flagDelete = 0;
|
||||
char flagCode = 0;
|
||||
|
||||
char match = 0;
|
||||
unsigned offset = 0;
|
||||
for(unsigned n = 0; n < text.size();) {
|
||||
char x = text[n], y = text[n + 1];
|
||||
char a = n ? text[n - 1] : 0;
|
||||
char b = text[n];
|
||||
char c = text[n++ + 1];
|
||||
|
||||
if(x == '[' && y == '\\') { output.append('['); n += 2; continue; }
|
||||
bool d = !a || a == ' ' || a == '\t' || a == '\r' || a == '\n'; //is previous character whitespace?
|
||||
bool e = !c || c == ' ' || c == '\t' || c == '\r' || c == '\n'; //is next character whitespace?
|
||||
bool f = (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || (c >= '0' && c <= '9'); //is next character alphanumeric?
|
||||
|
||||
if(x == '[' && y == '*' && flagStrong == 0) { flagStrong = 1; output.append("<strong>"); n += 2; continue; }
|
||||
if(x == '*' && y == ']' && flagStrong == 1) { flagStrong = 0; output.append("</strong>"); n += 2; continue; }
|
||||
|
||||
if(x == '[' && y == '/' && flagEmphasis == 0) { flagEmphasis = 1; output.append("<em>"); n += 2; continue; }
|
||||
if(x == '/' && y == ']' && flagEmphasis == 1) { flagEmphasis = 0; output.append("</em>"); n += 2; continue; }
|
||||
|
||||
if(x == '[' && y == '_' && flagInsert == 0) { flagInsert = 1; output.append("<ins>"); n += 2; continue; }
|
||||
if(x == '_' && y == ']' && flagInsert == 1) { flagInsert = 0; output.append("</ins>"); n += 2; continue; }
|
||||
|
||||
if(x == '[' && y == '-' && flagDelete == 0) { flagDelete = 1; output.append("<del>"); n += 2; continue; }
|
||||
if(x == '-' && y == ']' && flagDelete == 1) { flagDelete = 0; output.append("</del>"); n += 2; continue; }
|
||||
|
||||
if(x == '[' && y == '|' && flagCode == 0) { flagCode = 1; output.append("<code>"); n += 2; continue; }
|
||||
if(x == '|' && y == ']' && flagCode == 1) { flagCode = 0; output.append("</code>"); n += 2; continue; }
|
||||
|
||||
if(x == '[' && y == '[') {
|
||||
if(auto length = text.findFrom(n + 2, "]]")) {
|
||||
lstring content = text.slice(n + 2, *length).split<1>(" => ");
|
||||
output.append("<a href=\"", escape(content[0]), "\">", escape(content(1, content[0])), "</a>");
|
||||
n += *length + 4;
|
||||
continue;
|
||||
}
|
||||
if(!match && d && !e) {
|
||||
if(b == '*') { match = '*'; offset = n; continue; }
|
||||
if(b == '/') { match = '/'; offset = n; continue; }
|
||||
if(b == '_') { match = '_'; offset = n; continue; }
|
||||
if(b == '~') { match = '~'; offset = n; continue; }
|
||||
if(b == '|') { match = '|'; offset = n; continue; }
|
||||
if(b == '[') { match = ']'; offset = n; continue; }
|
||||
if(b == '{') { match = '}'; offset = n; continue; }
|
||||
}
|
||||
|
||||
if(x == '[' && y == '{') {
|
||||
if(auto length = text.findFrom(n + 2, "}]")) {
|
||||
lstring content = text.slice(n + 2, *length).split<1>(" => ");
|
||||
output.append("<img src=\"", escape(content[0]), "\" alt=\"", escape(content(1, "")), "\">");
|
||||
n += *length + 4;
|
||||
//if we reach the end of the string without a match; force a match so the content is still output
|
||||
if(match && b != match && !c) { b = match; f = 0; n++; }
|
||||
|
||||
if(match && b == match && !f) {
|
||||
match = 0;
|
||||
auto content = text.slice(offset, n - offset - 1);
|
||||
if(b == '*') { output.append("<strong>", escape(content), "</strong>"); continue; }
|
||||
if(b == '/') { output.append("<em>", escape(content), "</em>"); continue; }
|
||||
if(b == '_') { output.append("<ins>", escape(content), "</ins>"); continue; }
|
||||
if(b == '~') { output.append("<del>", escape(content), "</del>"); continue; }
|
||||
if(b == '|') { output.append("<code>", escape(content), "</code>"); continue; }
|
||||
if(b == ']') {
|
||||
auto p = content.split(" => ", 1L);
|
||||
p[0].replace("@/", settings.host);
|
||||
output.append("<a href=\"", escape(p[0]), "\">", escape(p(1, p[0])), "</a>");
|
||||
continue;
|
||||
}
|
||||
if(b == '}') {
|
||||
auto p = content.split(" => ", 1L);
|
||||
p[0].replace("@/", settings.host);
|
||||
output.append("<img src=\"", escape(p[0]), "\" alt=\"", escape(p(1, "")), "\">");
|
||||
continue;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if(x == '&') { output.append("&"); n++; continue; }
|
||||
if(x == '<') { output.append("<"); n++; continue; }
|
||||
if(x == '>') { output.append(">"); n++; continue; }
|
||||
if(x == '"') { output.append("""); n++; continue; }
|
||||
|
||||
output.append(x);
|
||||
n++;
|
||||
if(match) continue;
|
||||
if(b == '\\' && c) { output.append(c); n++; continue; } //character escaping
|
||||
if(b == '&') { output.append("&"); continue; } //entity escaping
|
||||
if(b == '<') { output.append("<"); continue; } //...
|
||||
if(b == '>') { output.append(">"); continue; } //...
|
||||
if(b == '"') { output.append("""); continue; } //...
|
||||
output.append(b);
|
||||
}
|
||||
|
||||
if(flagStrong) output.append("</strong>");
|
||||
if(flagEmphasis) output.append("</em>");
|
||||
if(flagInsert) output.append("</ins>");
|
||||
if(flagDelete) output.append("</del>");
|
||||
if(flagCode) output.append("</code>");
|
||||
return output;
|
||||
}
|
||||
|
||||
|
|
|
@ -2,69 +2,92 @@
|
|||
|
||||
namespace nall {
|
||||
|
||||
auto trim(string& self, rstring lhs, rstring rhs) -> bool {
|
||||
if(lhs.size() + rhs.size() > self.size()) return false;
|
||||
if(memory::compare(self.data(), lhs.data(), lhs.size()) != 0) return false;
|
||||
if(memory::compare(self.data() + self.size() - rhs.size(), rhs.data(), rhs.size()) != 0) return false;
|
||||
self.resize(self.size() - rhs.size());
|
||||
self.remove(0, lhs.size());
|
||||
return true;
|
||||
auto trim(string& self, rstring lhs, rstring rhs, long limit) -> string& {
|
||||
rtrim(self, rhs, limit);
|
||||
ltrim(self, lhs, limit);
|
||||
return self;
|
||||
}
|
||||
|
||||
auto ltrim(string& self, rstring lhs) -> bool {
|
||||
if(lhs.size() > self.size()) return false;
|
||||
if(memory::compare(self.data(), lhs.data(), lhs.size()) != 0) return false;
|
||||
self.remove(0, lhs.size());
|
||||
return true;
|
||||
auto ltrim(string& self, rstring lhs, long limit) -> string& {
|
||||
if(lhs.size() == 0) return self;
|
||||
long matches = 0;
|
||||
while(matches < limit) {
|
||||
signed offset = lhs.size() * matches;
|
||||
signed size = (signed)self.size() - offset;
|
||||
if(size < (signed)lhs.size()) break;
|
||||
if(memory::compare(self.data() + offset, lhs.data(), lhs.size()) != 0) break;
|
||||
matches++;
|
||||
}
|
||||
if(matches) self.remove(0, lhs.size() * matches);
|
||||
return self;
|
||||
}
|
||||
|
||||
auto rtrim(string& self, rstring rhs) -> bool {
|
||||
if(rhs.size() > self.size()) return false;
|
||||
if(memory::compare(self.data() + self.size() - rhs.size(), rhs.data(), rhs.size()) != 0) return false;
|
||||
self.resize(self.size() - rhs.size());
|
||||
return true;
|
||||
auto rtrim(string& self, rstring rhs, long limit) -> string& {
|
||||
if(rhs.size() == 0) return self;
|
||||
long matches = 0;
|
||||
while(matches < limit) {
|
||||
signed offset = (signed)self.size() - rhs.size() * (matches + 1);
|
||||
signed size = (signed)self.size() - offset;
|
||||
if(offset < 0 || size < (signed)rhs.size()) break;
|
||||
if(memory::compare(self.data() + offset, rhs.data(), rhs.size()) != 0) break;
|
||||
matches++;
|
||||
}
|
||||
if(matches) self.resize(self.size() - rhs.size() * matches);
|
||||
return self;
|
||||
}
|
||||
|
||||
auto itrim(string& self, rstring lhs, rstring rhs) -> bool {
|
||||
if(lhs.size() + rhs.size() > self.size()) return false;
|
||||
if(memory::icompare(self.data(), lhs.data(), lhs.size()) != 0) return false;
|
||||
if(memory::icompare(self.data() + self.size() - rhs.size(), rhs.data(), rhs.size()) != 0) return false;
|
||||
self.resize(self.size() - rhs.size());
|
||||
self.remove(0, lhs.size());
|
||||
return true;
|
||||
auto itrim(string& self, rstring lhs, rstring rhs, long limit) -> string& {
|
||||
irtrim(self, rhs, limit);
|
||||
iltrim(self, lhs, limit);
|
||||
return self;
|
||||
}
|
||||
|
||||
auto iltrim(string& self, rstring lhs) -> bool {
|
||||
if(lhs.size() > self.size()) return false;
|
||||
if(memory::icompare(self.data(), lhs.data(), lhs.size()) != 0) return false;
|
||||
self.remove(0, lhs.size());
|
||||
return true;
|
||||
auto iltrim(string& self, rstring lhs, long limit) -> string& {
|
||||
if(lhs.size() == 0) return self;
|
||||
long matches = 0;
|
||||
while(matches < limit) {
|
||||
signed offset = lhs.size() * matches;
|
||||
signed size = (signed)self.size() - offset;
|
||||
if(size < (signed)lhs.size()) break;
|
||||
if(memory::icompare(self.data() + offset, lhs.data(), lhs.size()) != 0) break;
|
||||
matches++;
|
||||
}
|
||||
if(matches) self.remove(0, lhs.size() * matches);
|
||||
return self;
|
||||
}
|
||||
|
||||
auto irtrim(string& self, rstring rhs) -> bool {
|
||||
if(rhs.size() > self.size()) return false;
|
||||
if(memory::icompare(self.data() + self.size() - rhs.size(), rhs.data(), rhs.size()) != 0) return false;
|
||||
self.resize(self.size() - rhs.size());
|
||||
return true;
|
||||
auto irtrim(string& self, rstring rhs, long limit) -> string& {
|
||||
if(rhs.size() == 0) return self;
|
||||
long matches = 0;
|
||||
while(matches < limit) {
|
||||
signed offset = (signed)self.size() - rhs.size() * (matches + 1);
|
||||
signed size = (signed)self.size() - offset;
|
||||
if(offset < 0 || size < (signed)rhs.size()) break;
|
||||
if(memory::icompare(self.data() + offset, rhs.data(), rhs.size()) != 0) break;
|
||||
matches++;
|
||||
}
|
||||
if(matches) self.resize(self.size() - rhs.size() * matches);
|
||||
return self;
|
||||
}
|
||||
|
||||
auto strip(string& self) -> bool {
|
||||
return rstrip(self) | lstrip(self);
|
||||
auto strip(string& self) -> string& {
|
||||
rstrip(self);
|
||||
lstrip(self);
|
||||
return self;
|
||||
}
|
||||
|
||||
auto lstrip(string& self) -> bool {
|
||||
auto lstrip(string& self) -> string& {
|
||||
unsigned size = 0;
|
||||
while(size < self.size()) {
|
||||
char input = self[size];
|
||||
if(input != ' ' && input != '\t' && input != '\r' && input != '\n') break;
|
||||
size++;
|
||||
}
|
||||
if(size == 0) return false;
|
||||
self.remove(0, size);
|
||||
return true;
|
||||
if(size) self.remove(0, size);
|
||||
return self;
|
||||
}
|
||||
|
||||
auto rstrip(string& self) -> bool {
|
||||
auto rstrip(string& self) -> string& {
|
||||
unsigned size = 0;
|
||||
while(size < self.size()) {
|
||||
bool matched = false;
|
||||
|
@ -72,9 +95,8 @@ auto rstrip(string& self) -> bool {
|
|||
if(input != ' ' && input != '\t' && input != '\r' && input != '\n') break;
|
||||
size++;
|
||||
}
|
||||
if(size == 0) return false;
|
||||
self.resize(self.size() - size);
|
||||
return true;
|
||||
if(size) self.resize(self.size() - size);
|
||||
return self;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -22,9 +22,8 @@ auto string::read(const string& filename) -> string {
|
|||
return fclose(fp), result;
|
||||
}
|
||||
|
||||
template<unsigned L> auto string::repeat(const string& pattern) -> string {
|
||||
auto string::repeat(const string& pattern, unsigned times) -> string {
|
||||
string result;
|
||||
unsigned times = L;
|
||||
while(times--) result.append(pattern);
|
||||
return result;
|
||||
}
|
||||
|
|
|
@ -6,11 +6,11 @@
|
|||
namespace nall {
|
||||
|
||||
template<typename T> struct base_from_member {
|
||||
T value;
|
||||
base_from_member(T value) : value(value) {}
|
||||
T value;
|
||||
};
|
||||
|
||||
template<typename T> inline T* allocate(unsigned size, const T& value) {
|
||||
template<typename T> inline auto allocate(unsigned size, const T& value) -> T* {
|
||||
T* array = new T[size];
|
||||
for(unsigned i = 0; i < size; i++) array[i] = value;
|
||||
return array;
|
||||
|
|
139
nall/varint.hpp
139
nall/varint.hpp
|
@ -9,10 +9,10 @@
|
|||
namespace nall {
|
||||
|
||||
struct varint {
|
||||
virtual uint8_t read() = 0;
|
||||
virtual void write(uint8_t) = 0;
|
||||
virtual auto read() -> uint8_t = 0;
|
||||
virtual auto write(uint8_t) -> void = 0;
|
||||
|
||||
uintmax_t readvu() {
|
||||
auto readvu() -> uintmax_t {
|
||||
uintmax_t data = 0, shift = 1;
|
||||
while(true) {
|
||||
uint8_t x = read();
|
||||
|
@ -24,7 +24,7 @@ struct varint {
|
|||
return data;
|
||||
}
|
||||
|
||||
intmax_t readvs() {
|
||||
auto readvs() -> intmax_t {
|
||||
uintmax_t data = readvu();
|
||||
bool sign = data & 1;
|
||||
data >>= 1;
|
||||
|
@ -32,7 +32,7 @@ struct varint {
|
|||
return data;
|
||||
}
|
||||
|
||||
void writevu(uintmax_t data) {
|
||||
auto writevu(uintmax_t data) -> void {
|
||||
while(true) {
|
||||
uint8_t x = data & 0x7f;
|
||||
data >>= 7;
|
||||
|
@ -42,7 +42,7 @@ struct varint {
|
|||
}
|
||||
}
|
||||
|
||||
void writevs(intmax_t data) {
|
||||
auto writevs(intmax_t data) -> void {
|
||||
bool sign = data < 0;
|
||||
if(sign) data = -data;
|
||||
data = (data << 1) | sign;
|
||||
|
@ -51,97 +51,96 @@ struct varint {
|
|||
};
|
||||
|
||||
template<unsigned bits> struct uint_t {
|
||||
private:
|
||||
using type_t = type_if<expression<bits <= 8 * sizeof(unsigned)>, unsigned, uintmax_t>;
|
||||
type_t data;
|
||||
|
||||
public:
|
||||
inline operator type_t() const { return data; }
|
||||
inline type_t operator ++(int) { type_t r = data; data = uclip<bits>(data + 1); return r; }
|
||||
inline type_t operator --(int) { type_t r = data; data = uclip<bits>(data - 1); return r; }
|
||||
inline type_t operator ++() { return data = uclip<bits>(data + 1); }
|
||||
inline type_t operator --() { return data = uclip<bits>(data - 1); }
|
||||
inline type_t operator =(const type_t i) { return data = uclip<bits>(i); }
|
||||
inline type_t operator |=(const type_t i) { return data = uclip<bits>(data | i); }
|
||||
inline type_t operator ^=(const type_t i) { return data = uclip<bits>(data ^ i); }
|
||||
inline type_t operator &=(const type_t i) { return data = uclip<bits>(data & i); }
|
||||
inline type_t operator<<=(const type_t i) { return data = uclip<bits>(data << i); }
|
||||
inline type_t operator>>=(const type_t i) { return data = uclip<bits>(data >> i); }
|
||||
inline type_t operator +=(const type_t i) { return data = uclip<bits>(data + i); }
|
||||
inline type_t operator -=(const type_t i) { return data = uclip<bits>(data - i); }
|
||||
inline type_t operator *=(const type_t i) { return data = uclip<bits>(data * i); }
|
||||
inline type_t operator /=(const type_t i) { return data = uclip<bits>(data / i); }
|
||||
inline type_t operator %=(const type_t i) { return data = uclip<bits>(data % i); }
|
||||
inline auto operator ++(int) { type_t r = data; data = uclip<bits>(data + 1); return r; }
|
||||
inline auto operator --(int) { type_t r = data; data = uclip<bits>(data - 1); return r; }
|
||||
inline auto operator ++() { return data = uclip<bits>(data + 1); }
|
||||
inline auto operator --() { return data = uclip<bits>(data - 1); }
|
||||
inline auto operator =(const type_t i) { return data = uclip<bits>(i); }
|
||||
inline auto operator |=(const type_t i) { return data = uclip<bits>(data | i); }
|
||||
inline auto operator ^=(const type_t i) { return data = uclip<bits>(data ^ i); }
|
||||
inline auto operator &=(const type_t i) { return data = uclip<bits>(data & i); }
|
||||
inline auto operator<<=(const type_t i) { return data = uclip<bits>(data << i); }
|
||||
inline auto operator>>=(const type_t i) { return data = uclip<bits>(data >> i); }
|
||||
inline auto operator +=(const type_t i) { return data = uclip<bits>(data + i); }
|
||||
inline auto operator -=(const type_t i) { return data = uclip<bits>(data - i); }
|
||||
inline auto operator *=(const type_t i) { return data = uclip<bits>(data * i); }
|
||||
inline auto operator /=(const type_t i) { return data = uclip<bits>(data / i); }
|
||||
inline auto operator %=(const type_t i) { return data = uclip<bits>(data % i); }
|
||||
|
||||
inline uint_t() : data(0) {}
|
||||
inline uint_t(const type_t i) : data(uclip<bits>(i)) {}
|
||||
|
||||
template<unsigned s> inline type_t operator=(const uint_t<s> &i) { return data = uclip<bits>((type_t)i); }
|
||||
template<unsigned s> inline uint_t(const uint_t<s> &i) : data(uclip<bits>(i)) {}
|
||||
template<unsigned s> inline uint_t(const uint_t<s>& i) : data(uclip<bits>(i)) {}
|
||||
template<unsigned s> inline auto operator=(const uint_t<s>& i) { return data = uclip<bits>((type_t)i); }
|
||||
|
||||
void serialize(serializer& s) { s(data); }
|
||||
auto serialize(serializer& s) { s(data); }
|
||||
|
||||
private:
|
||||
type_t data;
|
||||
};
|
||||
|
||||
template<unsigned bits> struct int_t {
|
||||
private:
|
||||
using type_t = type_if<expression<bits <= 8 * sizeof(signed)>, signed, intmax_t>;
|
||||
type_t data;
|
||||
|
||||
public:
|
||||
inline operator type_t() const { return data; }
|
||||
inline type_t operator ++(int) { type_t r = data; data = sclip<bits>(data + 1); return r; }
|
||||
inline type_t operator --(int) { type_t r = data; data = sclip<bits>(data - 1); return r; }
|
||||
inline type_t operator ++() { return data = sclip<bits>(data + 1); }
|
||||
inline type_t operator --() { return data = sclip<bits>(data - 1); }
|
||||
inline type_t operator =(const type_t i) { return data = sclip<bits>(i); }
|
||||
inline type_t operator |=(const type_t i) { return data = sclip<bits>(data | i); }
|
||||
inline type_t operator ^=(const type_t i) { return data = sclip<bits>(data ^ i); }
|
||||
inline type_t operator &=(const type_t i) { return data = sclip<bits>(data & i); }
|
||||
inline type_t operator<<=(const type_t i) { return data = sclip<bits>(data << i); }
|
||||
inline type_t operator>>=(const type_t i) { return data = sclip<bits>(data >> i); }
|
||||
inline type_t operator +=(const type_t i) { return data = sclip<bits>(data + i); }
|
||||
inline type_t operator -=(const type_t i) { return data = sclip<bits>(data - i); }
|
||||
inline type_t operator *=(const type_t i) { return data = sclip<bits>(data * i); }
|
||||
inline type_t operator /=(const type_t i) { return data = sclip<bits>(data / i); }
|
||||
inline type_t operator %=(const type_t i) { return data = sclip<bits>(data % i); }
|
||||
inline auto operator ++(int) { type_t r = data; data = sclip<bits>(data + 1); return r; }
|
||||
inline auto operator --(int) { type_t r = data; data = sclip<bits>(data - 1); return r; }
|
||||
inline auto operator ++() { return data = sclip<bits>(data + 1); }
|
||||
inline auto operator --() { return data = sclip<bits>(data - 1); }
|
||||
inline auto operator =(const type_t i) { return data = sclip<bits>(i); }
|
||||
inline auto operator |=(const type_t i) { return data = sclip<bits>(data | i); }
|
||||
inline auto operator ^=(const type_t i) { return data = sclip<bits>(data ^ i); }
|
||||
inline auto operator &=(const type_t i) { return data = sclip<bits>(data & i); }
|
||||
inline auto operator<<=(const type_t i) { return data = sclip<bits>(data << i); }
|
||||
inline auto operator>>=(const type_t i) { return data = sclip<bits>(data >> i); }
|
||||
inline auto operator +=(const type_t i) { return data = sclip<bits>(data + i); }
|
||||
inline auto operator -=(const type_t i) { return data = sclip<bits>(data - i); }
|
||||
inline auto operator *=(const type_t i) { return data = sclip<bits>(data * i); }
|
||||
inline auto operator /=(const type_t i) { return data = sclip<bits>(data / i); }
|
||||
inline auto operator %=(const type_t i) { return data = sclip<bits>(data % i); }
|
||||
|
||||
inline int_t() : data(0) {}
|
||||
inline int_t(const type_t i) : data(sclip<bits>(i)) {}
|
||||
|
||||
template<unsigned s> inline type_t operator=(const int_t<s> &i) { return data = sclip<bits>((type_t)i); }
|
||||
template<unsigned s> inline int_t(const int_t<s> &i) : data(sclip<bits>(i)) {}
|
||||
template<unsigned s> inline int_t(const int_t<s>& i) : data(sclip<bits>(i)) {}
|
||||
template<unsigned s> inline auto operator=(const int_t<s>& i) { return data = sclip<bits>((type_t)i); }
|
||||
|
||||
void serialize(serializer& s) { s(data); }
|
||||
auto serialize(serializer& s) { s(data); }
|
||||
|
||||
private:
|
||||
type_t data;
|
||||
};
|
||||
|
||||
template<typename type_t> struct varuint_t {
|
||||
private:
|
||||
type_t data;
|
||||
type_t mask;
|
||||
|
||||
public:
|
||||
inline operator type_t() const { return data; }
|
||||
inline type_t operator ++(int) { type_t r = data; data = (data + 1) & mask; return r; }
|
||||
inline type_t operator --(int) { type_t r = data; data = (data - 1) & mask; return r; }
|
||||
inline type_t operator ++() { return data = (data + 1) & mask; }
|
||||
inline type_t operator --() { return data = (data - 1) & mask; }
|
||||
inline type_t operator =(const type_t i) { return data = (i) & mask; }
|
||||
inline type_t operator |=(const type_t i) { return data = (data | i) & mask; }
|
||||
inline type_t operator ^=(const type_t i) { return data = (data ^ i) & mask; }
|
||||
inline type_t operator &=(const type_t i) { return data = (data & i) & mask; }
|
||||
inline type_t operator<<=(const type_t i) { return data = (data << i) & mask; }
|
||||
inline type_t operator>>=(const type_t i) { return data = (data >> i) & mask; }
|
||||
inline type_t operator +=(const type_t i) { return data = (data + i) & mask; }
|
||||
inline type_t operator -=(const type_t i) { return data = (data - i) & mask; }
|
||||
inline type_t operator *=(const type_t i) { return data = (data * i) & mask; }
|
||||
inline type_t operator /=(const type_t i) { return data = (data / i) & mask; }
|
||||
inline type_t operator %=(const type_t i) { return data = (data % i) & mask; }
|
||||
inline auto operator ++(int) { type_t r = data; data = (data + 1) & mask; return r; }
|
||||
inline auto operator --(int) { type_t r = data; data = (data - 1) & mask; return r; }
|
||||
inline auto operator ++() { return data = (data + 1) & mask; }
|
||||
inline auto operator --() { return data = (data - 1) & mask; }
|
||||
inline auto operator =(const type_t i) { return data = (i) & mask; }
|
||||
inline auto operator |=(const type_t i) { return data = (data | i) & mask; }
|
||||
inline auto operator ^=(const type_t i) { return data = (data ^ i) & mask; }
|
||||
inline auto operator &=(const type_t i) { return data = (data & i) & mask; }
|
||||
inline auto operator<<=(const type_t i) { return data = (data << i) & mask; }
|
||||
inline auto operator>>=(const type_t i) { return data = (data >> i) & mask; }
|
||||
inline auto operator +=(const type_t i) { return data = (data + i) & mask; }
|
||||
inline auto operator -=(const type_t i) { return data = (data - i) & mask; }
|
||||
inline auto operator *=(const type_t i) { return data = (data * i) & mask; }
|
||||
inline auto operator /=(const type_t i) { return data = (data / i) & mask; }
|
||||
inline auto operator %=(const type_t i) { return data = (data % i) & mask; }
|
||||
|
||||
inline void bits(type_t bits) { mask = (1ull << (bits - 1)) + ((1ull << (bits - 1)) - 1); data &= mask; }
|
||||
inline auto bits(type_t bits) { mask = (1ull << (bits - 1)) + ((1ull << (bits - 1)) - 1); data &= mask; }
|
||||
inline varuint_t() : data(0ull), mask((type_t)~0ull) {}
|
||||
inline varuint_t(const type_t i) : data(i), mask((type_t)~0ull) {}
|
||||
|
||||
void serialize(serializer& s) { s(data); s(mask); }
|
||||
auto serialize(serializer& s) { s(data); s(mask); }
|
||||
|
||||
private:
|
||||
type_t data;
|
||||
type_t mask;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
109
nall/vector.hpp
109
nall/vector.hpp
|
@ -17,22 +17,15 @@ namespace nall {
|
|||
template<typename T> struct vector {
|
||||
struct exception_out_of_bounds{};
|
||||
|
||||
protected:
|
||||
T* pool = nullptr;
|
||||
unsigned poolbase = 0;
|
||||
unsigned poolsize = 0;
|
||||
unsigned objectsize = 0;
|
||||
|
||||
public:
|
||||
explicit operator bool() const { return objectsize; }
|
||||
T* data() { return pool + poolbase; }
|
||||
const T* data() const { return pool + poolbase; }
|
||||
auto data() -> T* { return pool + poolbase; }
|
||||
auto data() const -> const T* { return pool + poolbase; }
|
||||
|
||||
bool empty() const { return objectsize == 0; }
|
||||
unsigned size() const { return objectsize; }
|
||||
unsigned capacity() const { return poolsize; }
|
||||
auto empty() const -> bool { return objectsize == 0; }
|
||||
auto size() const -> unsigned { return objectsize; }
|
||||
auto capacity() const -> unsigned { return poolsize; }
|
||||
|
||||
T* move() {
|
||||
auto move() -> T* {
|
||||
T* result = pool + poolbase;
|
||||
pool = nullptr;
|
||||
poolbase = 0;
|
||||
|
@ -41,7 +34,7 @@ public:
|
|||
return result;
|
||||
}
|
||||
|
||||
void reset() {
|
||||
auto reset() -> void {
|
||||
if(pool) {
|
||||
for(unsigned n = 0; n < objectsize; n++) pool[poolbase + n].~T();
|
||||
memory::free(pool);
|
||||
|
@ -52,7 +45,7 @@ public:
|
|||
objectsize = 0;
|
||||
}
|
||||
|
||||
void reserve(unsigned size) {
|
||||
auto reserve(unsigned size) -> void {
|
||||
if(size <= poolsize) return;
|
||||
size = bit::round(size); //amortize growth
|
||||
|
||||
|
@ -64,7 +57,7 @@ public:
|
|||
poolsize = size;
|
||||
}
|
||||
|
||||
void resize(unsigned size, T value = T()) {
|
||||
auto resize(unsigned size, T value = T()) -> void {
|
||||
T* copy = (T*)memory::allocate(size * sizeof(T));
|
||||
for(unsigned n = 0; n < size && n < objectsize; n++) new(copy + n) T(std::move(pool[poolbase + n]));
|
||||
for(unsigned n = objectsize; n < size; n++) new(copy + n) T(value);
|
||||
|
@ -75,17 +68,17 @@ public:
|
|||
objectsize = size;
|
||||
}
|
||||
|
||||
void reallocate(unsigned size, T value = T()) {
|
||||
auto reallocate(unsigned size, T value = T()) -> void {
|
||||
reset();
|
||||
resize(size, value);
|
||||
}
|
||||
|
||||
template<typename... Args> void prepend(const T& data, Args&&... args) {
|
||||
prepend(std::forward<Args>(args)...);
|
||||
template<typename... Args> auto prepend(const T& data, Args&&... args) -> void {
|
||||
prepend(forward<Args>(args)...);
|
||||
prepend(data);
|
||||
}
|
||||
|
||||
T& prepend(const T& data) {
|
||||
auto prepend(const T& data) -> T& {
|
||||
reserve(objectsize + 1);
|
||||
if(poolbase == 0) {
|
||||
unsigned available = poolsize - objectsize;
|
||||
|
@ -99,23 +92,23 @@ public:
|
|||
return first();
|
||||
}
|
||||
|
||||
template<typename... Args> void append(const T& data, Args&&... args) {
|
||||
template<typename... Args> auto append(const T& data, Args&&... args) -> void {
|
||||
append(data);
|
||||
append(std::forward<Args>(args)...);
|
||||
append(forward<Args>(args)...);
|
||||
}
|
||||
|
||||
T& append(const T& data) {
|
||||
auto append(const T& data) -> T& {
|
||||
reserve(poolbase + objectsize + 1);
|
||||
new(pool + poolbase + objectsize++) T(data);
|
||||
return last();
|
||||
}
|
||||
|
||||
bool appendOnce(const T& data) {
|
||||
auto appendOnce(const T& data) -> bool {
|
||||
if(find(data)) return false;
|
||||
return append(data), true;
|
||||
}
|
||||
|
||||
void insert(unsigned position, const T& data) {
|
||||
auto insert(unsigned position, const T& data) -> void {
|
||||
if(position == 0) {
|
||||
prepend(data);
|
||||
return;
|
||||
|
@ -128,7 +121,7 @@ public:
|
|||
pool[poolbase + position] = data;
|
||||
}
|
||||
|
||||
void remove(unsigned position = ~0u, unsigned length = 1) {
|
||||
auto remove(unsigned position = ~0u, unsigned length = 1) -> void {
|
||||
if(position == ~0u) position = objectsize - 1;
|
||||
if(position + length > objectsize) throw exception_out_of_bounds{};
|
||||
|
||||
|
@ -147,112 +140,112 @@ public:
|
|||
objectsize -= length;
|
||||
}
|
||||
|
||||
void removeFirst() { return remove(0); }
|
||||
void removeLast() { return remove(~0u); }
|
||||
auto removeFirst() -> void { return remove(0); }
|
||||
auto removeLast() -> void { return remove(~0u); }
|
||||
|
||||
T take(unsigned position = ~0u) {
|
||||
auto take(unsigned position = ~0u) -> T {
|
||||
if(position == ~0u) position = objectsize - 1;
|
||||
T object = pool[poolbase + position];
|
||||
remove(position);
|
||||
return object;
|
||||
}
|
||||
|
||||
T takeFirst() { return take(0); }
|
||||
T takeLast() { return take(~0u); }
|
||||
auto takeFirst() -> T { return take(0); }
|
||||
auto takeLast() -> T { return take(~0u); }
|
||||
|
||||
void reverse() {
|
||||
auto reverse() -> void {
|
||||
unsigned pivot = size() / 2;
|
||||
for(unsigned l = 0, r = size() - 1; l < pivot; l++, r--) {
|
||||
std::swap(pool[poolbase + l], pool[poolbase + r]);
|
||||
}
|
||||
}
|
||||
|
||||
void sort() {
|
||||
auto sort() -> void {
|
||||
nall::sort(pool + poolbase, objectsize);
|
||||
}
|
||||
|
||||
template<typename Comparator> void sort(const Comparator &lessthan) {
|
||||
template<typename Comparator> auto sort(const Comparator& lessthan) -> void {
|
||||
nall::sort(pool + poolbase, objectsize, lessthan);
|
||||
}
|
||||
|
||||
maybe<unsigned> find(const T& data) const {
|
||||
auto find(const T& data) const -> maybe<unsigned> {
|
||||
for(unsigned n = 0; n < objectsize; n++) if(pool[poolbase + n] == data) return n;
|
||||
return nothing;
|
||||
}
|
||||
|
||||
T& first() {
|
||||
auto first() -> T& {
|
||||
if(objectsize == 0) throw exception_out_of_bounds();
|
||||
return pool[poolbase];
|
||||
}
|
||||
|
||||
const T& first() const {
|
||||
auto first() const -> const T& {
|
||||
if(objectsize == 0) throw exception_out_of_bounds();
|
||||
return pool[poolbase];
|
||||
}
|
||||
|
||||
T& last() {
|
||||
auto last() -> T& {
|
||||
if(objectsize == 0) throw exception_out_of_bounds();
|
||||
return pool[poolbase + objectsize - 1];
|
||||
}
|
||||
|
||||
const T& last() const {
|
||||
auto last() const -> const T& {
|
||||
if(objectsize == 0) throw exception_out_of_bounds();
|
||||
return pool[poolbase + objectsize - 1];
|
||||
}
|
||||
|
||||
//access
|
||||
inline T& operator[](unsigned position) {
|
||||
inline auto operator[](unsigned position) -> T& {
|
||||
if(position >= objectsize) throw exception_out_of_bounds();
|
||||
return pool[poolbase + position];
|
||||
}
|
||||
|
||||
inline const T& operator[](unsigned position) const {
|
||||
inline auto operator[](unsigned position) const -> const T& {
|
||||
if(position >= objectsize) throw exception_out_of_bounds();
|
||||
return pool[poolbase + position];
|
||||
}
|
||||
|
||||
inline T& operator()(unsigned position) {
|
||||
inline auto operator()(unsigned position) -> T& {
|
||||
if(position >= poolsize) reserve(position + 1);
|
||||
while(position >= objectsize) append(T());
|
||||
return pool[poolbase + position];
|
||||
}
|
||||
|
||||
inline const T& operator()(unsigned position, const T& data) const {
|
||||
inline auto operator()(unsigned position, const T& data) const -> const T& {
|
||||
if(position >= objectsize) return data;
|
||||
return pool[poolbase + position];
|
||||
}
|
||||
|
||||
//iteration
|
||||
struct iterator {
|
||||
T& operator*() { return source.operator[](position); }
|
||||
bool operator!=(const iterator& source) const { return position != source.position; }
|
||||
iterator& operator++() { position++; return *this; }
|
||||
iterator(vector& source, unsigned position) : source(source), position(position) {}
|
||||
auto operator*() -> T& { return source.operator[](position); }
|
||||
auto operator!=(const iterator& source) const -> bool { return position != source.position; }
|
||||
auto operator++() -> iterator& { position++; return *this; }
|
||||
|
||||
private:
|
||||
vector& source;
|
||||
unsigned position;
|
||||
};
|
||||
|
||||
iterator begin() { return iterator(*this, 0); }
|
||||
iterator end() { return iterator(*this, size()); }
|
||||
auto begin() -> iterator { return iterator(*this, 0); }
|
||||
auto end() -> iterator { return iterator(*this, size()); }
|
||||
|
||||
struct constIterator {
|
||||
const T& operator*() const { return source.operator[](position); }
|
||||
bool operator!=(const constIterator& source) const { return position != source.position; }
|
||||
constIterator& operator++() { position++; return *this; }
|
||||
constIterator(const vector& source, unsigned position) : source(source), position(position) {}
|
||||
auto operator*() const -> const T& { return source.operator[](position); }
|
||||
auto operator!=(const constIterator& source) const -> bool { return position != source.position; }
|
||||
auto operator++() -> constIterator& { position++; return *this; }
|
||||
|
||||
private:
|
||||
const vector& source;
|
||||
unsigned position;
|
||||
};
|
||||
|
||||
const constIterator begin() const { return constIterator(*this, 0); }
|
||||
const constIterator end() const { return constIterator(*this, size()); }
|
||||
auto begin() const -> const constIterator { return constIterator(*this, 0); }
|
||||
auto end() const -> const constIterator { return constIterator(*this, size()); }
|
||||
|
||||
//copy
|
||||
inline vector& operator=(const vector& source) {
|
||||
inline auto operator=(const vector& source) -> vector& {
|
||||
if(this == &source) return *this;
|
||||
reset();
|
||||
reserve(source.size());
|
||||
|
@ -261,7 +254,7 @@ public:
|
|||
}
|
||||
|
||||
//move
|
||||
inline vector& operator=(vector&& source) {
|
||||
inline auto operator=(vector&& source) -> vector& {
|
||||
if(this == &source) return *this;
|
||||
reset();
|
||||
pool = source.pool;
|
||||
|
@ -281,6 +274,12 @@ public:
|
|||
vector(const vector& source) { operator=(source); }
|
||||
vector(vector&& source) { operator=(std::move(source)); }
|
||||
~vector() { reset(); }
|
||||
|
||||
protected:
|
||||
T* pool = nullptr;
|
||||
unsigned poolbase = 0;
|
||||
unsigned poolsize = 0;
|
||||
unsigned objectsize = 0;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -75,7 +75,7 @@ bool detour::insert(const string& moduleName, const string& functionName, void*&
|
|||
#if 1
|
||||
string output = { "detour::insert(", moduleName, "::", functionName, ") failed: " };
|
||||
for(unsigned n = 0; n < 16; n++) output.append(hex<2>(sourceData[n]), " ");
|
||||
output.rtrim(" ");
|
||||
output.rtrim(" ", 1L);
|
||||
MessageBoxA(0, output, "nall::detour", MB_OK);
|
||||
#endif
|
||||
return false;
|
||||
|
|
|
@ -30,10 +30,10 @@ auto ARM::disassemble_arm_instruction(uint32 pc) -> string {
|
|||
static auto is_comp = [](uint4 opcode) { return opcode >= 8 && opcode <= 11; };
|
||||
static auto is_math = [](uint4 opcode) { return opcode < 8 || opcode == 12 || opcode == 14; };
|
||||
|
||||
string output{hex<8>(pc), " "};
|
||||
string output{hex(pc, 8L), " "};
|
||||
|
||||
uint32 instruction = read(Word | Nonsequential, pc & ~3);
|
||||
output.append(hex<8>(instruction), " ");
|
||||
output.append(hex(instruction, 8L), " ");
|
||||
|
||||
//multiply()
|
||||
//mul{condition}{s} rd,rm,rs
|
||||
|
@ -130,11 +130,11 @@ auto ARM::disassemble_arm_instruction(uint32 pc) -> string {
|
|||
output.append(load ? "ldr" : "str", conditions[condition], "h ");
|
||||
output.append(registers[rd], ",[", registers[rn]);
|
||||
if(pre == 0) output.append("]");
|
||||
if(immediate) output.append(",", up ? "+" : "-", "0x", hex<2>(immediate));
|
||||
if(immediate) output.append(",", up ? "+" : "-", "0x", hex(immediate, 2L));
|
||||
if(pre == 1) output.append("]");
|
||||
if(pre == 0 || writeback == 1) output.append("!");
|
||||
|
||||
if(rn == 15) output.append(" =0x", hex<4>(read(Half | Nonsequential, pc + 8 + (up ? +immediate : -immediate))));
|
||||
if(rn == 15) output.append(" =0x", hex(read(Half | Nonsequential, pc + 8 + (up ? +immediate : -immediate)), 4L));
|
||||
return output;
|
||||
}
|
||||
|
||||
|
@ -180,12 +180,12 @@ auto ARM::disassemble_arm_instruction(uint32 pc) -> string {
|
|||
output.append("ldr", conditions[condition], half ? "sh " : "sb ");
|
||||
output.append(registers[rd], ",[", registers[rn]);
|
||||
if(pre == 0) output.append("]");
|
||||
if(immediate) output.append(",", up ? "+" : "-", "0x", hex<2>(immediate));
|
||||
if(immediate) output.append(",", up ? "+" : "-", "0x", hex(immediate, 2L));
|
||||
if(pre == 1) output.append("]");
|
||||
if(pre == 0 || writeback == 1) output.append("!");
|
||||
|
||||
if(rn == 15 && half == 1) output.append(" =0x", hex<4>(read(Half | Nonsequential, pc + 8 + (up ? +immediate : -immediate))));
|
||||
if(rn == 15 && half == 0) output.append(" =0x", hex<2>(read(Byte | Nonsequential, pc + 8 + (up ? +immediate : -immediate))));
|
||||
if(rn == 15 && half == 1) output.append(" =0x", hex(read(Half | Nonsequential, pc + 8 + (up ? +immediate : -immediate)), 4L));
|
||||
if(rn == 15 && half == 0) output.append(" =0x", hex(read(Byte | Nonsequential, pc + 8 + (up ? +immediate : -immediate)), 2L));
|
||||
return output;
|
||||
}
|
||||
|
||||
|
@ -254,7 +254,7 @@ auto ARM::disassemble_arm_instruction(uint32 pc) -> string {
|
|||
field & 4 ? "s" : "",
|
||||
field & 8 ? "f" : ""
|
||||
);
|
||||
output.append(",#0x", hex<8>(immediate));
|
||||
output.append(",#0x", hex(immediate, 8L));
|
||||
|
||||
return output;
|
||||
}
|
||||
|
@ -333,7 +333,7 @@ auto ARM::disassemble_arm_instruction(uint32 pc) -> string {
|
|||
if(is_move(opcode)) output.append(save ? "s " : " ", registers[rd]);
|
||||
if(is_comp(opcode)) output.append(" ", registers[rn]);
|
||||
if(is_math(opcode)) output.append(save ? "s " : " ", registers[rd], ",", registers[rn]);
|
||||
output.append(",#0x", hex<8>(rm));
|
||||
output.append(",#0x", hex(rm, 8L));
|
||||
|
||||
return output;
|
||||
}
|
||||
|
@ -355,11 +355,11 @@ auto ARM::disassemble_arm_instruction(uint32 pc) -> string {
|
|||
output.append(load ? "ldr" : "str", conditions[condition], byte ? "b " : " ");
|
||||
output.append(registers[rd], ",[", registers[rn]);
|
||||
if(pre == 0) output.append("]");
|
||||
if(immediate) output.append(",", up ? "+" : "-", "0x", hex<3>(immediate));
|
||||
if(immediate) output.append(",", up ? "+" : "-", "0x", hex(immediate, 3L));
|
||||
if(pre == 1) output.append("]");
|
||||
if(pre == 0 || writeback == 1) output.append("!");
|
||||
|
||||
if(rn == 15) output.append(" =0x", hex<8>(read((byte ? Byte : Word) | Nonsequential, pc + 8 + (up ? +immediate : -immediate))));
|
||||
if(rn == 15) output.append(" =0x", hex(read((byte ? Byte : Word) | Nonsequential, pc + 8 + (up ? +immediate : -immediate)), 8L));
|
||||
return output;
|
||||
}
|
||||
|
||||
|
@ -421,7 +421,7 @@ auto ARM::disassemble_arm_instruction(uint32 pc) -> string {
|
|||
uint1 link = instruction >> 24;
|
||||
|
||||
output.append("b", link ? "l" : "", conditions[condition], " ");
|
||||
output.append("0x", hex<8>(pc + 8 + (int24)instruction * 4));
|
||||
output.append("0x", hex(pc + 8 + (int24)instruction * 4, 8L));
|
||||
|
||||
return output;
|
||||
}
|
||||
|
@ -431,7 +431,7 @@ auto ARM::disassemble_arm_instruction(uint32 pc) -> string {
|
|||
if((instruction & 0x0f000000) == 0x0f000000) {
|
||||
uint24 immediate = instruction;
|
||||
|
||||
output.append("swi #0x", hex<6>(immediate));
|
||||
output.append("swi #0x", hex(immediate, 6L));
|
||||
|
||||
return output;
|
||||
}
|
||||
|
@ -455,10 +455,10 @@ auto ARM::disassemble_thumb_instruction(uint32 pc) -> string {
|
|||
"r12", "sp", "lr", "pc",
|
||||
};
|
||||
|
||||
string output{hex<8>(pc), " "};
|
||||
string output{hex(pc, 8L), " "};
|
||||
|
||||
uint16 instruction = read(Half | Nonsequential, pc & ~1);
|
||||
output.append(hex<4>(instruction), " ");
|
||||
output.append(hex(instruction, 4L), " ");
|
||||
|
||||
//adjust_register()
|
||||
//(add,sub) rd,rn,rm
|
||||
|
@ -481,7 +481,7 @@ auto ARM::disassemble_thumb_instruction(uint32 pc) -> string {
|
|||
uint3 rn = instruction >> 3;
|
||||
uint3 rd = instruction >> 0;
|
||||
|
||||
output.append(opcode == 0 ? "add" : "sub", " ", registers[rd], ",", registers[rn], ",#", hex<1>(immediate));
|
||||
output.append(opcode == 0 ? "add" : "sub", " ", registers[rd], ",", registers[rn], ",#", hex(immediate, 1L));
|
||||
|
||||
return output;
|
||||
}
|
||||
|
@ -510,7 +510,7 @@ auto ARM::disassemble_thumb_instruction(uint32 pc) -> string {
|
|||
uint3 rd = instruction >> 8;
|
||||
uint8 immediate = instruction;
|
||||
|
||||
output.append(opcodes[opcode], " ", registers[rd], ",#0x", hex<2>(immediate));
|
||||
output.append(opcodes[opcode], " ", registers[rd], ",#0x", hex(immediate, 2L));
|
||||
|
||||
return output;
|
||||
}
|
||||
|
@ -570,8 +570,8 @@ auto ARM::disassemble_thumb_instruction(uint32 pc) -> string {
|
|||
uint8 displacement = instruction;
|
||||
|
||||
unsigned rm = ((pc + 4) & ~3) + displacement * 4;
|
||||
output.append("ldr ", registers[rd], ",[pc,#0x", hex<3>(rm), "]");
|
||||
output.append(" =0x", hex<8>(read(Word | Nonsequential, rm)));
|
||||
output.append("ldr ", registers[rd], ",[pc,#0x", hex(rm, 3L), "]");
|
||||
output.append(" =0x", hex(read(Word | Nonsequential, rm), 8L));
|
||||
|
||||
return output;
|
||||
}
|
||||
|
@ -602,7 +602,7 @@ auto ARM::disassemble_thumb_instruction(uint32 pc) -> string {
|
|||
uint3 rn = instruction >> 3;
|
||||
uint3 rd = instruction >> 0;
|
||||
|
||||
output.append(load ? "ldr " : "str ", registers[rd], ",[", registers[rn], ",#0x", hex<2>(offset * 4), "]");
|
||||
output.append(load ? "ldr " : "str ", registers[rd], ",[", registers[rn], ",#0x", hex(offset * 4, 2L), "]");
|
||||
|
||||
return output;
|
||||
}
|
||||
|
@ -615,7 +615,7 @@ auto ARM::disassemble_thumb_instruction(uint32 pc) -> string {
|
|||
uint3 rn = instruction >> 3;
|
||||
uint3 rd = instruction >> 0;
|
||||
|
||||
output.append(load ? "ldrb " : "strb ", registers[rd], ",[", registers[rn], ",#0x", hex<2>(offset), "]");
|
||||
output.append(load ? "ldrb " : "strb ", registers[rd], ",[", registers[rn], ",#0x", hex(offset, 2L), "]");
|
||||
|
||||
return output;
|
||||
}
|
||||
|
@ -628,7 +628,7 @@ auto ARM::disassemble_thumb_instruction(uint32 pc) -> string {
|
|||
uint3 rn = instruction >> 3;
|
||||
uint3 rd = instruction >> 0;
|
||||
|
||||
output.append(load ? "ldrh " : "strh ", registers[rd], ",[", registers[rn], ",#0x", hex<2>(offset * 2), "]");
|
||||
output.append(load ? "ldrh " : "strh ", registers[rd], ",[", registers[rn], ",#0x", hex(offset * 2, 2L), "]");
|
||||
|
||||
return output;
|
||||
}
|
||||
|
@ -640,7 +640,7 @@ auto ARM::disassemble_thumb_instruction(uint32 pc) -> string {
|
|||
uint3 rd = instruction >> 8;
|
||||
int8 relative = instruction;
|
||||
|
||||
output.append(opcode ? "ldr" : "str", " ", registers[rd], ",[sp,#0x", hex<3>(relative * 4), "]");
|
||||
output.append(opcode ? "ldr" : "str", " ", registers[rd], ",[sp,#0x", hex(relative * 4, 3L), "]");
|
||||
|
||||
return output;
|
||||
}
|
||||
|
@ -652,7 +652,7 @@ auto ARM::disassemble_thumb_instruction(uint32 pc) -> string {
|
|||
uint3 rd = instruction >> 8;
|
||||
uint8 immediate = instruction;
|
||||
|
||||
output.append("add ", registers[rd], ",", sp ? "sp" : "pc", ",#0x", hex<2>(immediate));
|
||||
output.append("add ", registers[rd], ",", sp ? "sp" : "pc", ",#0x", hex(immediate, 2L));
|
||||
|
||||
return output;
|
||||
}
|
||||
|
@ -663,7 +663,7 @@ auto ARM::disassemble_thumb_instruction(uint32 pc) -> string {
|
|||
uint1 opcode = instruction >> 7;
|
||||
uint7 immediate = instruction;
|
||||
|
||||
output.append(opcode == 0 ? "add" : "sub", " sp,#0x", hex<3>(immediate * 4));
|
||||
output.append(opcode == 0 ? "add" : "sub", " sp,#0x", hex(immediate * 4, 3L));
|
||||
|
||||
return output;
|
||||
}
|
||||
|
@ -709,7 +709,7 @@ auto ARM::disassemble_thumb_instruction(uint32 pc) -> string {
|
|||
if((instruction & 0xff00) == 0xdf00) {
|
||||
uint8 immediate = instruction;
|
||||
|
||||
output.append("swi #0x", hex<2>(immediate));
|
||||
output.append("swi #0x", hex(immediate, 2L));
|
||||
|
||||
return output;
|
||||
}
|
||||
|
@ -721,7 +721,7 @@ auto ARM::disassemble_thumb_instruction(uint32 pc) -> string {
|
|||
int8 displacement = instruction;
|
||||
|
||||
uint32 offset = pc + 4 + displacement * 2;
|
||||
output.append("b", conditions[condition], " 0x", hex<8>(offset));
|
||||
output.append("b", conditions[condition], " 0x", hex(offset, 8L));
|
||||
|
||||
return output;
|
||||
}
|
||||
|
@ -731,7 +731,7 @@ auto ARM::disassemble_thumb_instruction(uint32 pc) -> string {
|
|||
if((instruction & 0xf800) == 0xe000) {
|
||||
int11 displacement = instruction;
|
||||
|
||||
output.append("b 0x", hex<8>(pc + 4 + displacement * 2));
|
||||
output.append("b 0x", hex(pc + 4 + displacement * 2, 8L));
|
||||
|
||||
return output;
|
||||
}
|
||||
|
@ -744,7 +744,7 @@ auto ARM::disassemble_thumb_instruction(uint32 pc) -> string {
|
|||
uint11 offsetlo = instruction;
|
||||
|
||||
int22 displacement = (offsethi << 11) | (offsetlo << 0);
|
||||
output.append("bl 0x", hex<8>(pc + 4 + displacement * 2));
|
||||
output.append("bl 0x", hex(pc + 4 + displacement * 2, 8L));
|
||||
|
||||
return output;
|
||||
}
|
||||
|
@ -763,18 +763,18 @@ auto ARM::disassemble_thumb_instruction(uint32 pc) -> string {
|
|||
|
||||
auto ARM::disassemble_registers() -> string {
|
||||
string output;
|
||||
output.append( "r0:", hex<8>(r( 0)), " r1:", hex<8>(r( 1)), " r2:", hex<8>(r( 2)), " r3:", hex<8>(r( 3)), " ");
|
||||
output.append( "r4:", hex<8>(r( 4)), " r5:", hex<8>(r( 5)), " r6:", hex<8>(r( 6)), " r7:", hex<8>(r( 7)), " ");
|
||||
output.append( "r0:", hex(r( 0), 8L), " r1:", hex(r( 1), 8L), " r2:", hex(r( 2), 8L), " r3:", hex(r( 3), 8L), " ");
|
||||
output.append( "r4:", hex(r( 4), 8L), " r5:", hex(r( 5), 8L), " r6:", hex(r( 6), 8L), " r7:", hex(r( 7), 8L), " ");
|
||||
output.append("cpsr:", cpsr().n ? "N" : "n", cpsr().z ? "Z" : "z", cpsr().c ? "C" : "c", cpsr().v ? "V" : "v");
|
||||
output.append("/", cpsr().i ? "I" : "i", cpsr().f ? "F" : "f", cpsr().t ? "T" : "t");
|
||||
output.append("/", hex<2>(cpsr().m), "\n");
|
||||
output.append( "r8:", hex<8>(r( 8)), " r9:", hex<8>(r( 9)), " r10:", hex<8>(r(10)), " r11:", hex<8>(r(11)), " ");
|
||||
output.append("r12:", hex<8>(r(12)), " sp:", hex<8>(r(13)), " lr:", hex<8>(r(14)), " pc:", hex<8>(r(15)), " ");
|
||||
output.append("/", hex(cpsr().m, 2L), "\n");
|
||||
output.append( "r8:", hex(r( 8), 8L), " r9:", hex(r( 9), 8L), " r10:", hex(r(10), 8L), " r11:", hex(r(11), 8L), " ");
|
||||
output.append("r12:", hex(r(12), 8L), " sp:", hex(r(13), 8L), " lr:", hex(r(14), 8L), " pc:", hex(r(15), 8L), " ");
|
||||
output.append("spsr:");
|
||||
if(mode() == Processor::Mode::USR || mode() == Processor::Mode::SYS) { output.append("----/---/--"); return output; }
|
||||
output.append( spsr().n ? "N" : "n", spsr().z ? "Z" : "z", spsr().c ? "C" : "c", spsr().v ? "V" : "v");
|
||||
output.append("/", spsr().i ? "I" : "i", spsr().f ? "F" : "f", spsr().t ? "T" : "t");
|
||||
output.append("/", hex<2>(spsr().m));
|
||||
output.append("/", hex(spsr().m, 2L));
|
||||
return output;
|
||||
}
|
||||
|
||||
|
|
|
@ -348,7 +348,7 @@ void HG51B::instruction() {
|
|||
}
|
||||
|
||||
else {
|
||||
print("Hitachi DSP: unknown opcode @ ", hex<4>(regs.pc - 1), " = ", hex<4>(opcode), "\n");
|
||||
print("Hitachi DSP: unknown opcode @ ", hex(regs.pc - 1, 4L), " = ", hex(opcode, 4L), "\n");
|
||||
regs.halt = true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,14 +5,14 @@ string LR35902::disassemble(uint16 pc) {
|
|||
|
||||
string opcode = disassemble_opcode(pc);
|
||||
string registers = {
|
||||
" AF:", hex<4>(r[AF]),
|
||||
" BC:", hex<4>(r[BC]),
|
||||
" DE:", hex<4>(r[DE]),
|
||||
" HL:", hex<4>(r[HL]),
|
||||
" SP:", hex<4>(r[SP])
|
||||
" AF:", hex(r[AF], 4L),
|
||||
" BC:", hex(r[BC], 4L),
|
||||
" DE:", hex(r[DE], 4L),
|
||||
" HL:", hex(r[HL], 4L),
|
||||
" SP:", hex(r[SP], 4L)
|
||||
};
|
||||
|
||||
memcpy(output + 0, hex<4>(pc).data(), 4);
|
||||
memcpy(output + 0, hex(pc, 4L).data(), 4);
|
||||
memcpy(output + 6, opcode.data(), opcode.length());
|
||||
memcpy(output + 23, registers.data(), registers.length());
|
||||
output[63] = 0;
|
||||
|
@ -27,68 +27,68 @@ string LR35902::disassemble_opcode(uint16 pc) {
|
|||
|
||||
switch(opcode) {
|
||||
case 0x00: return { "nop" };
|
||||
case 0x01: return { "ld bc,$", hex<2>(p1), hex<2>(p0) };
|
||||
case 0x01: return { "ld bc,$", hex(p1, 2L), hex(p0, 2L) };
|
||||
case 0x02: return { "ld (bc),a" };
|
||||
case 0x03: return { "inc bc" };
|
||||
case 0x04: return { "inc b" };
|
||||
case 0x05: return { "dec b" };
|
||||
case 0x06: return { "ld b,$", hex<2>(p0) };
|
||||
case 0x06: return { "ld b,$", hex(p0, 2L) };
|
||||
case 0x07: return { "rlc a" };
|
||||
case 0x08: return { "ld ($", hex<2>(p1), hex<2>(p0), "),sp" };
|
||||
case 0x08: return { "ld ($", hex(p1, 2L), hex(p0, 2L), "),sp" };
|
||||
case 0x09: return { "add hl,bc" };
|
||||
case 0x0a: return { "ld a,(bc)" };
|
||||
case 0x0b: return { "dec bc" };
|
||||
case 0x0c: return { "inc c" };
|
||||
case 0x0d: return { "dec c" };
|
||||
case 0x0e: return { "ld c,$", hex<2>(p0) };
|
||||
case 0x0e: return { "ld c,$", hex(p0, 2L) };
|
||||
case 0x0f: return { "rrc a" };
|
||||
case 0x10: return { "stop" };
|
||||
case 0x11: return { "ld de,$", hex<2>(p1), hex<2>(p0) };
|
||||
case 0x11: return { "ld de,$", hex(p1, 2L), hex(p0, 2L) };
|
||||
case 0x12: return { "ld (de),a" };
|
||||
case 0x13: return { "inc de" };
|
||||
case 0x14: return { "inc d" };
|
||||
case 0x15: return { "dec d" };
|
||||
case 0x16: return { "ld d,$", hex<2>(p0) };
|
||||
case 0x16: return { "ld d,$", hex(p0, 2L) };
|
||||
case 0x17: return { "rl a" };
|
||||
case 0x18: return { "jr $", hex<4>(r[PC] + 2 + (int8)p0) };
|
||||
case 0x18: return { "jr $", hex(r[PC] + 2 + (int8)p0, 4L) };
|
||||
case 0x19: return { "add hl,de" };
|
||||
case 0x1a: return { "ld a,(de)" };
|
||||
case 0x1b: return { "dec de" };
|
||||
case 0x1c: return { "inc e" };
|
||||
case 0x1d: return { "dec e" };
|
||||
case 0x1e: return { "ld e,$", hex<2>(p0) };
|
||||
case 0x1e: return { "ld e,$", hex(p0, 2L) };
|
||||
case 0x1f: return { "rr a" };
|
||||
case 0x20: return { "jr nz,$", hex<4>(r[PC] + 2 + (int8)p0) };
|
||||
case 0x21: return { "ld hl,$", hex<2>(p1), hex<2>(p0) };
|
||||
case 0x20: return { "jr nz,$", hex(r[PC] + 2 + (int8)p0, 4L) };
|
||||
case 0x21: return { "ld hl,$", hex(p1, 2L), hex(p0, 2L) };
|
||||
case 0x22: return { "ldi (hl),a" };
|
||||
case 0x23: return { "inc hl" };
|
||||
case 0x24: return { "inc h" };
|
||||
case 0x25: return { "dec h" };
|
||||
case 0x26: return { "ld h,$", hex<2>(p0) };
|
||||
case 0x26: return { "ld h,$", hex(p0, 2L) };
|
||||
case 0x27: return { "daa" };
|
||||
case 0x28: return { "jr z,$", hex<4>(r[PC] + 2 + (int8)p0) };
|
||||
case 0x28: return { "jr z,$", hex(r[PC] + 2 + (int8)p0, 4L) };
|
||||
case 0x29: return { "add hl,hl" };
|
||||
case 0x2a: return { "ldi a,(hl)" };
|
||||
case 0x2b: return { "dec hl" };
|
||||
case 0x2c: return { "inc l" };
|
||||
case 0x2d: return { "dec l" };
|
||||
case 0x2e: return { "ld l,$", hex<2>(p0) };
|
||||
case 0x2e: return { "ld l,$", hex(p0, 2L) };
|
||||
case 0x2f: return { "cpl" };
|
||||
case 0x30: return { "jr nc,$", hex<4>(r[PC] + 2 + (int8)p0) };
|
||||
case 0x31: return { "ld sp,$", hex<2>(p1), hex<2>(p0) };
|
||||
case 0x30: return { "jr nc,$", hex(r[PC] + 2 + (int8)p0, 4L) };
|
||||
case 0x31: return { "ld sp,$", hex(p1, 2L), hex(p0, 2L) };
|
||||
case 0x32: return { "ldd (hl),a" };
|
||||
case 0x33: return { "inc sp" };
|
||||
case 0x34: return { "inc (hl)" };
|
||||
case 0x35: return { "dec (hl)" };
|
||||
case 0x36: return { "ld (hl),$", hex<2>(p0) };
|
||||
case 0x36: return { "ld (hl),$", hex(p0, 2L) };
|
||||
case 0x37: return { "scf" };
|
||||
case 0x38: return { "jr c,$", hex<4>(r[PC] + 2 + (int8)p0) };
|
||||
case 0x38: return { "jr c,$", hex(r[PC] + 2 + (int8)p0, 4L) };
|
||||
case 0x39: return { "add hl,sp" };
|
||||
case 0x3a: return { "ldd a,(hl)" };
|
||||
case 0x3b: return { "dec sp" };
|
||||
case 0x3c: return { "inc a" };
|
||||
case 0x3d: return { "dec a" };
|
||||
case 0x3e: return { "ld a,$", hex<2>(p0) };
|
||||
case 0x3e: return { "ld a,$", hex(p0, 2L) };
|
||||
case 0x3f: return { "ccf" };
|
||||
case 0x40: return { "ld b,b" };
|
||||
case 0x41: return { "ld b,c" };
|
||||
|
@ -220,67 +220,67 @@ string LR35902::disassemble_opcode(uint16 pc) {
|
|||
case 0xbf: return { "cp a,a" };
|
||||
case 0xc0: return { "ret nz" };
|
||||
case 0xc1: return { "pop bc" };
|
||||
case 0xc2: return { "jp nz,$", hex<2>(p1), hex<2>(p0) };
|
||||
case 0xc3: return { "jp $", hex<2>(p1), hex<2>(p0) };
|
||||
case 0xc4: return { "call nz,$", hex<2>(p1), hex<2>(p0) };
|
||||
case 0xc2: return { "jp nz,$", hex(p1, 2L), hex(p0, 2L) };
|
||||
case 0xc3: return { "jp $", hex(p1, 2L), hex(p0, 2L) };
|
||||
case 0xc4: return { "call nz,$", hex(p1, 2L), hex(p0, 2L) };
|
||||
case 0xc5: return { "push bc" };
|
||||
case 0xc6: return { "add a,$", hex<2>(p0) };
|
||||
case 0xc6: return { "add a,$", hex(p0, 2L) };
|
||||
case 0xc7: return { "rst $0000" };
|
||||
case 0xc8: return { "ret z" };
|
||||
case 0xc9: return { "ret" };
|
||||
case 0xca: return { "jp z,$", hex<2>(p1), hex<2>(p0) };
|
||||
case 0xca: return { "jp z,$", hex(p1, 2L), hex(p0, 2L) };
|
||||
case 0xcb: return disassemble_opcode_cb(pc + 1);
|
||||
case 0xcc: return { "call z,$", hex<2>(p1), hex<2>(p0) };
|
||||
case 0xcd: return { "call $", hex<2>(p1), hex<2>(p0) };
|
||||
case 0xce: return { "adc a,$", hex<2>(p0) };
|
||||
case 0xcc: return { "call z,$", hex(p1, 2L), hex(p0, 2L) };
|
||||
case 0xcd: return { "call $", hex(p1, 2L), hex(p0, 2L) };
|
||||
case 0xce: return { "adc a,$", hex(p0, 2L) };
|
||||
case 0xcf: return { "rst $0008" };
|
||||
case 0xd0: return { "ret nc" };
|
||||
case 0xd1: return { "pop de" };
|
||||
case 0xd2: return { "jp nc,$", hex<2>(p1), hex<2>(p0) };
|
||||
case 0xd2: return { "jp nc,$", hex(p1, 2L), hex(p0, 2L) };
|
||||
case 0xd3: return { "xx" };
|
||||
case 0xd4: return { "call nc,$", hex<2>(p1), hex<2>(p0) };
|
||||
case 0xd4: return { "call nc,$", hex(p1, 2L), hex(p0, 2L) };
|
||||
case 0xd5: return { "push de" };
|
||||
case 0xd6: return { "sub a,$", hex<2>(p0) };
|
||||
case 0xd6: return { "sub a,$", hex(p0, 2L) };
|
||||
case 0xd7: return { "rst $0010" };
|
||||
case 0xd8: return { "ret c" };
|
||||
case 0xd9: return { "reti" };
|
||||
case 0xda: return { "jp c,$", hex<2>(p1), hex<2>(p0) };
|
||||
case 0xda: return { "jp c,$", hex(p1, 2L), hex(p0, 2L) };
|
||||
case 0xdb: return { "xx" };
|
||||
case 0xdc: return { "call c,$", hex<2>(p1), hex<2>(p0) };
|
||||
case 0xdc: return { "call c,$", hex(p1, 2L), hex(p0, 2L) };
|
||||
case 0xdd: return { "xx" };
|
||||
case 0xde: return { "sbc a,$", hex<2>(p0) };
|
||||
case 0xde: return { "sbc a,$", hex(p0, 2L) };
|
||||
case 0xdf: return { "rst $0018" };
|
||||
case 0xe0: return { "ld ($ff", hex<2>(p0), "),a" };
|
||||
case 0xe0: return { "ld ($ff", hex(p0, 2L), "),a" };
|
||||
case 0xe1: return { "pop hl" };
|
||||
case 0xe2: return { "ld ($ff00+c),a" };
|
||||
case 0xe3: return { "xx" };
|
||||
case 0xe4: return { "xx" };
|
||||
case 0xe5: return { "push hl" };
|
||||
case 0xe6: return { "and a,$", hex<2>(p0) };
|
||||
case 0xe6: return { "and a,$", hex(p0, 2L) };
|
||||
case 0xe7: return { "rst $0020" };
|
||||
case 0xe8: return { "add sp,$", hex<4>((int8)p0) };
|
||||
case 0xe8: return { "add sp,$", hex((int8)p0, 4L) };
|
||||
case 0xe9: return { "jp hl" };
|
||||
case 0xea: return { "ld ($", hex<2>(p1), hex<2>(p0), "),a" };
|
||||
case 0xea: return { "ld ($", hex(p1, 2L), hex(p0, 2L), "),a" };
|
||||
case 0xeb: return { "xx" };
|
||||
case 0xec: return { "xx" };
|
||||
case 0xed: return { "xx" };
|
||||
case 0xee: return { "xor a,$", hex<2>(p0) };
|
||||
case 0xee: return { "xor a,$", hex(p0, 2L) };
|
||||
case 0xef: return { "rst $0028" };
|
||||
case 0xf0: return { "ld a,($ff", hex<2>(p0), ")" };
|
||||
case 0xf0: return { "ld a,($ff", hex(p0, 2L), ")" };
|
||||
case 0xf1: return { "pop af" };
|
||||
case 0xf2: return { "ld a,($ff00+c)" };
|
||||
case 0xf3: return { "di" };
|
||||
case 0xf4: return { "xx" };
|
||||
case 0xf5: return { "push af" };
|
||||
case 0xf6: return { "or a,$", hex<2>(p0) };
|
||||
case 0xf6: return { "or a,$", hex(p0, 2L) };
|
||||
case 0xf7: return { "rst $0030" };
|
||||
case 0xf8: return { "ld hl,sp+$", hex<4>((int8)p0) };
|
||||
case 0xf8: return { "ld hl,sp+$", hex((int8)p0, 4L) };
|
||||
case 0xf9: return { "ld sp,hl" };
|
||||
case 0xfa: return { "ld a,($", hex<2>(p1), hex<2>(p0), ")" };
|
||||
case 0xfa: return { "ld a,($", hex(p1, 2L), hex(p0, 2L), ")" };
|
||||
case 0xfb: return { "ei" };
|
||||
case 0xfc: return { "xx" };
|
||||
case 0xfd: return { "xx" };
|
||||
case 0xfe: return { "cp a,$", hex<2>(p0) };
|
||||
case 0xfe: return { "cp a,$", hex(p0, 2L) };
|
||||
case 0xff: return { "rst $0038" };
|
||||
}
|
||||
|
||||
|
|
|
@ -1,18 +1,18 @@
|
|||
string R6502::disassemble() {
|
||||
string output = { hex<4>(regs.pc), " " };
|
||||
string output = { hex(regs.pc, 4L), " " };
|
||||
|
||||
auto abs = [&]() -> string { return { "$", hex<2>(debugger_read(regs.pc + 2)), hex<2>(debugger_read(regs.pc + 1)) }; };
|
||||
auto abx = [&]() -> string { return { "$", hex<2>(debugger_read(regs.pc + 2)), hex<2>(debugger_read(regs.pc + 1)), ",x" }; };
|
||||
auto aby = [&]() -> string { return { "$", hex<2>(debugger_read(regs.pc + 2)), hex<2>(debugger_read(regs.pc + 1)), ",y" }; };
|
||||
auto iab = [&]() -> string { return { "($", hex<2>(debugger_read(regs.pc + 2)), hex<2>(debugger_read(regs.pc + 1)), ")" }; };
|
||||
auto imm = [&]() -> string { return { "#$", hex<2>(debugger_read(regs.pc + 1)) }; };
|
||||
auto abs = [&]() -> string { return { "$", hex(debugger_read(regs.pc + 2), 2L), hex(debugger_read(regs.pc + 1), 2L) }; };
|
||||
auto abx = [&]() -> string { return { "$", hex(debugger_read(regs.pc + 2), 2L), hex(debugger_read(regs.pc + 1), 2L), ",x" }; };
|
||||
auto aby = [&]() -> string { return { "$", hex(debugger_read(regs.pc + 2), 2L), hex(debugger_read(regs.pc + 1), 2L), ",y" }; };
|
||||
auto iab = [&]() -> string { return { "($", hex(debugger_read(regs.pc + 2), 2L), hex(debugger_read(regs.pc + 1), 2L), ")" }; };
|
||||
auto imm = [&]() -> string { return { "#$", hex(debugger_read(regs.pc + 1), 2L) }; };
|
||||
auto imp = [&]() -> string { return ""; };
|
||||
auto izx = [&]() -> string { return { "($", hex<2>(debugger_read(regs.pc + 1)), ",x)" }; };
|
||||
auto izy = [&]() -> string { return { "($", hex<2>(debugger_read(regs.pc + 1)), "),y" }; };
|
||||
auto rel = [&]() -> string { return { "$", hex<4>((regs.pc + 2) + (int8)debugger_read(regs.pc + 1)) }; };
|
||||
auto zpg = [&]() -> string { return { "$", hex<2>(debugger_read(regs.pc + 1)) }; };
|
||||
auto zpx = [&]() -> string { return { "$", hex<2>(debugger_read(regs.pc + 1)), ",x" }; };
|
||||
auto zpy = [&]() -> string { return { "$", hex<2>(debugger_read(regs.pc + 1)), ",y" }; };
|
||||
auto izx = [&]() -> string { return { "($", hex(debugger_read(regs.pc + 1), 2L), ",x)" }; };
|
||||
auto izy = [&]() -> string { return { "($", hex(debugger_read(regs.pc + 1), 2L), "),y" }; };
|
||||
auto rel = [&]() -> string { return { "$", hex((regs.pc + 2) + (int8)debugger_read(regs.pc + 1), 4L) }; };
|
||||
auto zpg = [&]() -> string { return { "$", hex(debugger_read(regs.pc + 1), 2L) }; };
|
||||
auto zpx = [&]() -> string { return { "$", hex(debugger_read(regs.pc + 1), 2L), ",x" }; };
|
||||
auto zpy = [&]() -> string { return { "$", hex(debugger_read(regs.pc + 1), 2L), ",y" }; };
|
||||
|
||||
#define op(byte, prefix, mode) \
|
||||
case byte: output.append(#prefix, " ", mode()); \
|
||||
|
@ -176,7 +176,7 @@ string R6502::disassemble() {
|
|||
op(0xfd, sbc, abx);
|
||||
op(0xfe, inc, abx);
|
||||
|
||||
default: output.append("$", hex<2>(opcode)); break;
|
||||
default: output.append("$", hex(opcode, 2L)); break;
|
||||
}
|
||||
|
||||
#undef op
|
||||
|
@ -185,7 +185,7 @@ string R6502::disassemble() {
|
|||
output.resize(20);
|
||||
|
||||
output.append(
|
||||
"A:", hex<2>(regs.a), " X:", hex<2>(regs.x), " Y:", hex<2>(regs.y), " S:", hex<2>(regs.s), " ",
|
||||
"A:", hex(regs.a, 2L), " X:", hex(regs.x, 2L), " Y:", hex(regs.y, 2L), " S:", hex(regs.s, 2L), " ",
|
||||
regs.p.n ? "N" : "n", regs.p.v ? "V" : "v", regs.p.d ? "D" : "d",
|
||||
regs.p.i ? "I" : "i", regs.p.z ? "Z" : "z", regs.p.c ? "C" : "c"
|
||||
);
|
||||
|
|
|
@ -8,13 +8,13 @@ string SPC700::disassemble_opcode(uint16 addr, bool p) {
|
|||
return pc + offset;
|
||||
};
|
||||
|
||||
auto a = [&] { return hex<4>((read(addr + 1) << 0) + (read(addr + 2) << 8)); };
|
||||
auto b = [&](unsigned n) { return hex<2>(read(addr + 1 + n)); };
|
||||
auto r = [&](unsigned r, unsigned n = 0) { return hex<4>(addr + r + (int8)read(addr + 1 + n)); };
|
||||
auto dp = [&](unsigned n) { return hex<3>((p << 8) + read(addr + 1 + n)); };
|
||||
auto a = [&] { return hex((read(addr + 1) << 0) + (read(addr + 2) << 8), 4L); };
|
||||
auto b = [&](unsigned n) { return hex(read(addr + 1 + n), 2L); };
|
||||
auto r = [&](unsigned r, unsigned n = 0) { return hex(addr + r + (int8)read(addr + 1 + n), 4L); };
|
||||
auto dp = [&](unsigned n) { return hex((p << 8) + read(addr + 1 + n), 3L); };
|
||||
auto ab = [&] {
|
||||
unsigned n = (read(addr + 1) << 0) + (read(addr + 2) << 8);
|
||||
return string{ hex<4>(n & 0x1fff), ":", hex<1>(n >> 13) };
|
||||
return string{ hex(n & 0x1fff, 4L), ":", hex(n >> 13, 1L) };
|
||||
};
|
||||
|
||||
auto mnemonic = [&]() -> string {
|
||||
|
@ -279,17 +279,17 @@ string SPC700::disassemble_opcode(uint16 addr, bool p) {
|
|||
throw;
|
||||
};
|
||||
|
||||
string output = { "..", hex<4>(addr), " ", mnemonic() };
|
||||
string output = { "..", hex(addr, 4L), " ", mnemonic() };
|
||||
|
||||
unsigned length = output.length();
|
||||
while(length++ < 30) output.append(" ");
|
||||
|
||||
output.append(
|
||||
"YA:", hex<4>(regs.ya),
|
||||
" A:", hex<2>(regs.a),
|
||||
" X:", hex<2>(regs.x),
|
||||
" Y:", hex<2>(regs.y),
|
||||
" S:", hex<2>(regs.s),
|
||||
"YA:", hex(regs.ya, 4L),
|
||||
" A:", hex(regs.a, 2L),
|
||||
" X:", hex(regs.x, 2L),
|
||||
" Y:", hex(regs.y, 2L),
|
||||
" S:", hex(regs.s, 2L),
|
||||
" ",
|
||||
regs.p.n ? "N" : "n",
|
||||
regs.p.v ? "V" : "v",
|
||||
|
|
|
@ -28,11 +28,11 @@ auto OpenGL::shader(const string& pathname) -> void {
|
|||
for(auto node : document["output"]) {
|
||||
string text = node.text();
|
||||
if(node.name() == "width") {
|
||||
if(text.endsWith("%")) relativeWidth = real(text.rtrim("%")) / 100.0;
|
||||
if(text.endsWith("%")) relativeWidth = real(text.rtrim("%", 1L)) / 100.0;
|
||||
else absoluteWidth = text.decimal();
|
||||
}
|
||||
if(node.name() == "height") {
|
||||
if(text.endsWith("%")) relativeHeight = real(text.rtrim("%")) / 100.0;
|
||||
if(text.endsWith("%")) relativeHeight = real(text.rtrim("%", 1L)) / 100.0;
|
||||
else absoluteHeight = text.decimal();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,9 +4,9 @@ auto OpenGLProgram::bind(OpenGL* instance, const Markup::Node& node, const strin
|
|||
modulo = glrModulo(node["modulo"].integer());
|
||||
|
||||
string w = node["width"].text(), h = node["height"].text();
|
||||
if(w.endsWith("%")) relativeWidth = real(w.rtrim("%")) / 100.0;
|
||||
if(w.endsWith("%")) relativeWidth = real(w.rtrim("%", 1L)) / 100.0;
|
||||
else absoluteWidth = w.decimal();
|
||||
if(h.endsWith("%")) relativeHeight = real(h.rtrim("%")) / 100.0;
|
||||
if(h.endsWith("%")) relativeHeight = real(h.rtrim("%", 1L)) / 100.0;
|
||||
else absoluteHeight = h.decimal();
|
||||
|
||||
format = glrFormat(node["format"].text());
|
||||
|
@ -78,7 +78,7 @@ auto OpenGLProgram::parse(OpenGL* instance, string& source) -> void {
|
|||
if(auto position = s.find("//")) s.resize(position()); //strip comments
|
||||
s.strip(); //remove extraneous whitespace
|
||||
if(s.match("#in ?*")) {
|
||||
s.ltrim("#in ").strip();
|
||||
s.ltrim("#in ", 1L).strip();
|
||||
if(auto setting = instance->settings.find({s})) {
|
||||
line = {"#define ", setting().name, " ", setting().value};
|
||||
} else {
|
||||
|
|
|
@ -42,9 +42,9 @@ void generate(const char* sourceFilename, const char* targetFilename) {
|
|||
opcode.opcode = hex(arguments[0]);
|
||||
array.append(opcode);
|
||||
|
||||
line.rtrim<1>(",");
|
||||
line.rtrim(",", 1L);
|
||||
if(line.endswith(" {")) {
|
||||
line.rtrim<1>("{ ");
|
||||
line.rtrim("{ ", 1L);
|
||||
sourceStart = currentLine + 1;
|
||||
break;
|
||||
}
|
||||
|
@ -52,7 +52,7 @@ void generate(const char* sourceFilename, const char* targetFilename) {
|
|||
|
||||
if(cycle_accurate == false) {
|
||||
foreach(opcode, array) {
|
||||
fp.print("case 0x", hex<2>(opcode.opcode), ": {\n");
|
||||
fp.print("case 0x", hex(opcode.opcode, 2L), ": {\n");
|
||||
|
||||
for(unsigned n = sourceStart; n < lines.size(); n++) {
|
||||
if(lines[n] == "}") break;
|
||||
|
@ -85,7 +85,7 @@ void generate(const char* sourceFilename, const char* targetFilename) {
|
|||
}
|
||||
} else {
|
||||
foreach(opcode, array) {
|
||||
fp.print("case 0x", hex<2>(opcode.opcode), ": {\n");
|
||||
fp.print("case 0x", hex(opcode.opcode, 2L), ": {\n");
|
||||
fp.print(" switch(opcode_cycle++) {\n");
|
||||
|
||||
for(unsigned n = sourceStart; n < lines.size(); n++) {
|
||||
|
@ -101,7 +101,7 @@ void generate(const char* sourceFilename, const char* targetFilename) {
|
|||
output = { " ", lines[n] };
|
||||
} else {
|
||||
lstring part;
|
||||
part.split<1>(":", lines[n]);
|
||||
part.split(":", lines[n], 1L);
|
||||
fp.print(" case ", (unsigned)decimal(part[0]), ":\n");
|
||||
output = { " ", part[1] };
|
||||
}
|
||||
|
|
|
@ -199,7 +199,7 @@ void Cartridge::parse_markup_event(Markup::Node root) {
|
|||
if(root["name"].text() == "Powerfest '94") event.board = Event::Board::Powerfest94;
|
||||
|
||||
event.revision = root["revision"].text() == "B" ? 2 : 1;
|
||||
lstring part = root["timer"].text().split<1>(":");
|
||||
lstring part = root["timer"].text().split(":", 1L);
|
||||
if(part.size() == 1) event.timer = decimal(part(0));
|
||||
if(part.size() == 2) event.timer = decimal(part(0)) * 60 + decimal(part(1));
|
||||
|
||||
|
|
|
@ -60,13 +60,13 @@ void Event::submitScore() {
|
|||
data.append("ba:", ba[0], ",", ba[1], "\n");
|
||||
}
|
||||
|
||||
/*lstring side = interface->server().split<1>("@");
|
||||
string username = side(0).split<1>(":")(0);
|
||||
string password = side(0).split<1>(":")(1);
|
||||
side(1).ltrim("http://");
|
||||
string hostname = side(1).split<1>("/")(0);
|
||||
string hostpath = side(1).split<1>("/")(1);
|
||||
side = hostname.split<1>(":");
|
||||
/*lstring side = interface->server().split("@", 1L);
|
||||
string username = side(0).split(":", 1L)(0);
|
||||
string password = side(0).split(":", 1L)(1);
|
||||
side(1).ltrim("http://", 1L);
|
||||
string hostname = side(1).split("/", 1L)(0);
|
||||
string hostpath = side(1).split("/", 1L)(1);
|
||||
side = hostname.split(":", 1L);
|
||||
hostname = side(0);
|
||||
string hostport = side(1);
|
||||
if(hostport.empty()) hostport = "80";
|
||||
|
|
|
@ -123,7 +123,7 @@ USART::USART(bool port) : Controller(port) {
|
|||
txdata = 0;
|
||||
|
||||
string filename = {interface->path(ID::SuperFamicom), "usart.so"};
|
||||
if(open_absolute(filename)) {
|
||||
if(openAbsolute(filename)) {
|
||||
init = sym("usart_init");
|
||||
main = sym("usart_main");
|
||||
if(init && main) create(Controller::Enter, 10000000);
|
||||
|
|
|
@ -40,13 +40,13 @@ void Bus::map_reset() {
|
|||
|
||||
void Bus::map_xml() {
|
||||
for(auto& m : cartridge.mapping) {
|
||||
lstring part = m.addr.split<1>(":");
|
||||
lstring part = m.addr.split(":", 1L);
|
||||
lstring banks = part(0).split(",");
|
||||
lstring addrs = part(1).split(",");
|
||||
for(auto& bank : banks) {
|
||||
for(auto& addr : addrs) {
|
||||
lstring bankpart = bank.split<1>("-");
|
||||
lstring addrpart = addr.split<1>("-");
|
||||
lstring bankpart = bank.split("-", 1L);
|
||||
lstring addrpart = addr.split("-", 1L);
|
||||
unsigned banklo = hex(bankpart(0));
|
||||
unsigned bankhi = hex(bankpart(1, bankpart(0)));
|
||||
unsigned addrlo = hex(addrpart(0));
|
||||
|
|
|
@ -102,7 +102,7 @@ Presentation::Presentation() {
|
|||
|
||||
onClose([&] { program->quit(); });
|
||||
|
||||
setTitle({"tomoko v", Emulator::Version});
|
||||
setTitle({"higan v", Emulator::Version});
|
||||
setResizable(false);
|
||||
setBackgroundColor({0, 0, 0});
|
||||
resizeViewport();
|
||||
|
|
|
@ -3,7 +3,7 @@ auto Program::loadMedia(string location) -> void {
|
|||
if(!location.endsWith("/")) location.append("/");
|
||||
if(!directory::exists(location)) return;
|
||||
|
||||
string type = suffixname(location).ltrim(".");
|
||||
string type = suffixname(location).ltrim(".", 1L);
|
||||
for(auto& emulator : emulators) {
|
||||
for(auto& media : emulator->media) {
|
||||
if(media.bootable == false) continue;
|
||||
|
@ -13,14 +13,14 @@ auto Program::loadMedia(string location) -> void {
|
|||
}
|
||||
}
|
||||
|
||||
auto Program::loadMedia(Emulator::Interface& _emulator, Emulator::Interface::Media& media, const string& location) -> void {
|
||||
auto Program::loadMedia(Emulator::Interface& emulator_, Emulator::Interface::Media& media, const string& location) -> void {
|
||||
unloadMedia();
|
||||
|
||||
mediaPaths(0) = locate({userpath(), "Emulation/System/"}, {media.name, ".sys/"});
|
||||
mediaPaths(0) = locate({config->library.location, "System/"}, {media.name, ".sys/"});
|
||||
mediaPaths(media.id) = location;
|
||||
folderPaths.append(location);
|
||||
|
||||
emulator = &_emulator;
|
||||
emulator = &emulator_;
|
||||
emulator->load(media.id);
|
||||
updateVideoPalette();
|
||||
dsp.setFrequency(emulator->audioFrequency());
|
||||
|
@ -45,7 +45,7 @@ auto Program::unloadMedia() -> void {
|
|||
mediaPaths.reset();
|
||||
folderPaths.reset();
|
||||
|
||||
presentation->setTitle({"tomoko v", Emulator::Version});
|
||||
presentation->setTitle({"higan v", Emulator::Version});
|
||||
presentation->systemMenu.setVisible(false);
|
||||
presentation->toolsMenu.setVisible(false);
|
||||
toolsManager->setVisible(false);
|
||||
|
|
|
@ -2,7 +2,7 @@ auto Program::stateName(unsigned slot, bool manager) -> string {
|
|||
return {
|
||||
folderPaths[0], "higan/states/",
|
||||
manager ? "managed/" : "quick/",
|
||||
"slot-", decimal<2>(slot), ".bst"
|
||||
"slot-", decimal(slot, 2L), ".bst"
|
||||
};
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue