diff --git a/emulator/emulator.hpp b/emulator/emulator.hpp index 4697c77e..1349f888 100644 --- a/emulator/emulator.hpp +++ b/emulator/emulator.hpp @@ -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/"; diff --git a/hiro/components.hpp b/hiro/components.hpp index 6c03415d..e1a5a18d 100644 --- a/hiro/components.hpp +++ b/hiro/components.hpp @@ -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 diff --git a/hiro/extension/browser-dialog.cpp b/hiro/extension/browser-dialog.cpp index 1673b7a7..b283493e 100644 --- a/hiro/extension/browser-dialog.cpp +++ b/hiro/extension/browser-dialog.cpp @@ -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))) ); } diff --git a/hiro/gtk/browser-window.cpp b/hiro/gtk/browser-window.cpp index 9fed6d08..1cffbfd4 100644 --- a/hiro/gtk/browser-window.cpp +++ b/hiro/gtk/browser-window.cpp @@ -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); } diff --git a/hiro/gtk/font.cpp b/hiro/gtk/font.cpp index f5e09190..5addb5c6 100644 --- a/hiro/gtk/font.cpp +++ b/hiro/gtk/font.cpp @@ -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; diff --git a/hiro/gtk/widget/hex-edit.cpp b/hiro/gtk/widget/hex-edit.cpp index 49e1d75e..fe128353 100644 --- a/hiro/gtk/widget/hex-edit.cpp +++ b/hiro/gtk/widget/hex-edit.cpp @@ -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 { diff --git a/hiro/qt/font.cpp b/hiro/qt/font.cpp index 58542f67..ab964054 100644 --- a/hiro/qt/font.cpp +++ b/hiro/qt/font.cpp @@ -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; diff --git a/hiro/windows/browser-window.cpp b/hiro/windows/browser-window.cpp index eef3f47e..c439c935 100644 --- a/hiro/windows/browser-window.cpp +++ b/hiro/windows/browser-window.cpp @@ -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"); diff --git a/hiro/windows/font.cpp b/hiro/windows/font.cpp index f76baa79..80d240be 100644 --- a/hiro/windows/font.cpp +++ b/hiro/windows/font.cpp @@ -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; diff --git a/hiro/windows/widget/hex-edit.cpp b/hiro/windows/widget/hex-edit.cpp index 6a8f7880..c241675a 100644 --- a/hiro/windows/widget/hex-edit.cpp +++ b/hiro/windows/widget/hex-edit.cpp @@ -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 { diff --git a/nall/atoi.hpp b/nall/atoi.hpp index 86f05f32..5141e296 100644 --- a/nall/atoi.hpp +++ b/nall/atoi.hpp @@ -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); } diff --git a/nall/beat/archive.hpp b/nall/beat/archive.hpp index f3fce618..c5a8f652 100644 --- a/nall/beat/archive.hpp +++ b/nall/beat/archive.hpp @@ -1,84 +1,123 @@ #ifndef NALL_BEAT_ARCHIVE_HPP #define NALL_BEAT_ARCHIVE_HPP -#include +#include -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; - 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 { + 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 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 diff --git a/nall/beat/base.hpp b/nall/beat/base.hpp deleted file mode 100644 index 7d021d52..00000000 --- a/nall/beat/base.hpp +++ /dev/null @@ -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 diff --git a/nall/beat/file.hpp b/nall/beat/file.hpp new file mode 100644 index 00000000..37593900 --- /dev/null +++ b/nall/beat/file.hpp @@ -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 diff --git a/nall/beat/multi.hpp b/nall/beat/multi.hpp index 6d9428d6..a9e15796 100644 --- a/nall/beat/multi.hpp +++ b/nall/beat/multi.hpp @@ -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)); } } diff --git a/nall/bit.hpp b/nall/bit.hpp index c1cb15ee..818313e4 100644 --- a/nall/bit.hpp +++ b/nall/bit.hpp @@ -5,28 +5,28 @@ namespace nall { -template inline uintmax_t uclamp(const uintmax_t x) { +template 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 inline uintmax_t uclip(const uintmax_t x) { +template inline auto uclip(const uintmax_t x) -> uintmax_t { enum : uintmax_t { b = 1ull << (bits - 1), m = b * 2 - 1 }; return (x & m); } -template inline intmax_t sclamp(const intmax_t x) { +template 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 inline intmax_t sclip(const intmax_t x) { +template 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; diff --git a/nall/bitvector.hpp b/nall/bitvector.hpp index 0294b111..24e9d8e4 100644 --- a/nall/bitvector.hpp +++ b/nall/bitvector.hpp @@ -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; }; } diff --git a/nall/bmp.hpp b/nall/bmp.hpp index 9e68617e..6c39f13a 100644 --- a/nall/bmp.hpp +++ b/nall/bmp.hpp @@ -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; diff --git a/nall/config.hpp b/nall/config.hpp index b655b515..9937b764 100644 --- a/nall/config.hpp +++ b/nall/config.hpp @@ -15,11 +15,11 @@ struct Node { void* data = nullptr; vector 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 void append(T& data, const string& name, const string& desc = "") { + template 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); diff --git a/nall/database/odbc.hpp b/nall/database/odbc.hpp new file mode 100644 index 00000000..5abf2062 --- /dev/null +++ b/nall/database/odbc.hpp @@ -0,0 +1,274 @@ +#ifndef NALL_DATABASE_ODBC_HPP +#define NALL_DATABASE_ODBC_HPP + +#include + +#include +#include +#include + +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 { + vector 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 { 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& value) { return _bindings.append({column, any{(vector)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& value) { return bind(_input++, value); } + + auto step() -> bool { + if(!_stepped) { + for(auto& binding : _bindings) { + if(binding.value.is()) { + 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()) { + SQLBindParameter(_statement, 1 + binding.column, SQL_PARAM_INPUT, SQL_C_SLONG, SQL_INTEGER, 0, 0, &binding.value.get(), 0, nullptr); + } else if(binding.value.is()) { + SQLBindParameter(_statement, 1 + binding.column, SQL_PARAM_INPUT, SQL_C_ULONG, SQL_INTEGER, 0, 0, &binding.value.get(), 0, nullptr); + } else if(binding.value.is()) { + SQLBindParameter(_statement, 1 + binding.column, SQL_PARAM_INPUT, SQL_C_SBIGINT, SQL_INTEGER, 0, 0, &binding.value.get(), 0, nullptr); + } else if(binding.value.is()) { + SQLBindParameter(_statement, 1 + binding.column, SQL_PARAM_INPUT, SQL_C_UBIGINT, SQL_INTEGER, 0, 0, &binding.value.get(), 0, nullptr); + } else if(binding.value.is()) { + SQLBindParameter(_statement, 1 + binding.column, SQL_PARAM_INPUT, SQL_C_DOUBLE, SQL_DOUBLE, 0, 0, &binding.value.get(), 0, nullptr); + } else if(binding.value.is()) { + SQLLEN length = SQL_NTS; + SQLBindParameter(_statement, 1 + binding.column, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_VARCHAR, 0, 0, (SQLPOINTER)binding.value.get().data(), 0, &length); + } else if(binding.value.is>()) { + SQLLEN length = binding.value.get>().size(); + SQLBindParameter(_statement, 1 + binding.column, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_VARBINARY, 0, 0, (SQLPOINTER)binding.value.get>().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 _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 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)...); + return query; + } + +private: + auto success() const -> bool { return _result == SQL_SUCCESS || _result == SQL_SUCCESS_WITH_INFO; } + + auto bind(Query&) -> void {} + template auto bind(Query& query, const T& value, P&&... p) -> void { + query.bind(value); + bind(query, forward

(p)...); + } + + SQLHANDLE _environment = nullptr; + SQLHANDLE _connection = nullptr; + SQLRETURN _result = SQL_SUCCESS; +}; + +}} + +#endif diff --git a/nall/database/sqlite3.hpp b/nall/database/sqlite3.hpp index bd4b1791..6e03e14d 100644 --- a/nall/database/sqlite3.hpp +++ b/nall/database/sqlite3.hpp @@ -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& 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 { vector 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 { 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 { 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& 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& 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 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)...); + Query query{_statement}; + bind(query, forward

(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 auto _bind(Query& query, unsigned column, const T& value, P&&... p) -> void { - query.bind(column, value); - _bind(query, column + 1, forward

(p)...); + auto bind(Query&) -> void {} + template auto bind(Query& query, const T& value, P&&... p) -> void { + query.bind(value); + bind(query, forward

(p)...); } - bool debug = false; - sqlite3* database = nullptr; + bool _debug = false; + sqlite3* _database = nullptr; }; }} diff --git a/nall/directory.hpp b/nall/directory.hpp index f2983df6..1f19619e 100644 --- a/nall/directory.hpp +++ b/nall/directory.hpp @@ -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; diff --git a/nall/dl.hpp b/nall/dl.hpp index 289e3a9f..b7b1e653 100644 --- a/nall/dl.hpp +++ b/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 } diff --git a/nall/file.hpp b/nall/file.hpp index f73ec4b3..9bf15d9d 100644 --- a/nall/file.hpp +++ b/nall/file.hpp @@ -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++); } diff --git a/nall/filemap.hpp b/nall/filemap.hpp index 0c9ef5fa..5020ccfe 100644 --- a/nall/filemap.hpp +++ b/nall/filemap.hpp @@ -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(); } diff --git a/nall/function.hpp b/nall/function.hpp index fe7382f1..7c889600 100644 --- a/nall/function.hpp +++ b/nall/function.hpp @@ -5,52 +5,30 @@ namespace nall { -template class function; +template struct function; -template class function { - 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)...); } - container* copy() const { return new global(function); } - global(R (*function)(P...)) : function(function) {} - }; - - template struct member : container { - R (C::*function)(P...); - C* object; - R operator()(P... p) const { return (object->*function)(forward

(p)...); } - container* copy() const { return new member(function, object); } - member(R (C::*function)(P...), C* object) : function(function), object(object) {} - }; - - template struct lambda : container { - mutable L object; - R operator()(P... p) const { return object(forward

(p)...); } - container* copy() const { return new lambda(object); } - lambda(const L& object) : object(object) {} - }; - - //value = true if R L::operator()(P...) exists +template struct function { + //value = true if auto L::operator()(P...) -> R exists template struct is_compatible { - template static const typename is_same().operator()(declval

()...))>::type exists(T*); - template static const false_type exists(...); + template static auto exists(T*) -> const typename is_same().operator()(declval

()...))>::type; + template static auto exists(...) -> const false_type; static constexpr bool value = decltype(exists(0))::value; }; -public: - explicit operator bool() const { return callback; } - R operator()(P... p) const { return (*callback)(forward

(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 function(auto (C::*function)(P...) -> R, C* object) { callback = new member(function, object); } + template function(auto (C::*function)(P...) const -> R, C* object) { callback = new member((auto (C::*)(P...) -> R)function, object); } + template>> function(const L& object) { callback = new lambda(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)...); } + 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 function(R (C::*function)(P...), C* object) { callback = new member(function, object); } - template function(R (C::*function)(P...) const, C* object) { callback = new member((R (C::*)(P...))function, object); } - template>> function(const L& object) { callback = new lambda(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)...); } + auto copy() const -> container* { return new global(function); } + global(auto (*function)(P...) -> R) : function(function) {} + }; + + template struct member : container { + auto (C::*function)(P...) -> R; + C* object; + auto operator()(P... p) const -> R { return (object->*function)(forward

(p)...); } + auto copy() const -> container* { return new member(function, object); } + member(auto (C::*function)(P...) -> R, C* object) : function(function), object(object) {} + }; + + template struct lambda : container { + mutable L object; + auto operator()(P... p) const -> R { return object(forward

(p)...); } + auto copy() const -> container* { return new lambda(object); } + lambda(const L& object) : object(object) {} + }; }; } diff --git a/nall/group.hpp b/nall/group.hpp deleted file mode 100644 index f4ae68a2..00000000 --- a/nall/group.hpp +++ /dev/null @@ -1,66 +0,0 @@ -#ifndef NALL_GROUP_HPP -#define NALL_GROUP_HPP - -//group -//vector of unique references - -#include - -namespace nall { - -template struct group : protected vector { - group& operator=(const group& source) { vector::operator=(source); return *this; } - group& operator=(group&& source) { vector::operator=(std::move(source)); return *this; } - template group(Args&&... args) { construct(std::forward(args)...); } - - bool empty() const { return vector::empty(); } - unsigned size() const { return vector::size(); } - void reset() { vector::reset(); } - - T& first() const { return *vector::operator[](0); } - - //return true if at least one item was appended - template bool append(T& value, Args&&... args) { - bool result = append(value); - return append(std::forward(args)...) | result; - } - - bool append(T& value) { - if(vector::find(&value)) return false; - return vector::append(&value), true; - } - - //return true if at least one item was removed - template bool remove(T& value, Args&&... args) { - bool result = remove(value); - return remove(std::forward(args)...) | result; - } - - bool remove(T& value) { - if(auto position = vector::find(&value)) return vector::remove(position()), true; - return false; - } - - struct iterator : protected vector::constIterator { - T& operator*() const { return *vector::constIterator::operator*(); } - bool operator!=(const iterator& source) const { return vector::constIterator::operator!=(source); } - iterator& operator++() { vector::constIterator::operator++(); return *this; } - iterator(const group& source, unsigned position) : vector::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::operator=(source); } - void construct(group&& source) { vector::operator=(std::move(source)); } - template void construct(T& value, Args&&... args) { - append(value); - construct(std::forward(args)...); - } -}; - -} - -#endif diff --git a/nall/hashset.hpp b/nall/hashset.hpp index 58bc136f..2dc6367d 100644 --- a/nall/hashset.hpp +++ b/nall/hashset.hpp @@ -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 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 find(const T& value) { + auto find(const T& value) -> maybe { if(!pool) return nothing; unsigned hash = value.hash() & (length - 1); @@ -100,7 +94,7 @@ public: return nothing; } - maybe insert(const T& value) { + auto insert(const T& value) -> maybe { 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 }; } diff --git a/nall/http/request.hpp b/nall/http/request.hpp index bca7ae1e..a21676ea 100644 --- a/nall/http/request.hpp +++ b/nall/http/request.hpp @@ -18,9 +18,9 @@ struct httpRequest : httpMessage { inline auto body(const function& 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& 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)); } } diff --git a/nall/http/response.hpp b/nall/http/response.hpp index 7bca9201..07d80bc7 100644 --- a/nall/http/response.hpp +++ b/nall/http/response.hpp @@ -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]); } diff --git a/nall/http/server.hpp b/nall/http/server.hpp index 6718a29f..bd073af8 100644 --- a/nall/http/server.hpp +++ b/nall/http/server.hpp @@ -14,10 +14,22 @@ struct httpServer : httpRole, service { ~httpServer() { close(); } private: - signed fd = -1; function callback; - struct sockaddr_in addrin = {0}; std::atomic 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& function) -> void { @@ -82,15 +100,19 @@ auto httpServer::main(const function& 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(); } } diff --git a/nall/interpolation.hpp b/nall/interpolation.hpp index afc7108b..39a3c501 100644 --- a/nall/interpolation.hpp +++ b/nall/interpolation.hpp @@ -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; diff --git a/nall/map.hpp b/nall/map.hpp index 72c99ea5..a35f94d0 100644 --- a/nall/map.hpp +++ b/nall/map.hpp @@ -9,45 +9,47 @@ template 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 find(const T& key) const { + auto find(const T& key) const -> maybe { 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::iterator begin() { return root.begin(); } - typename set::iterator end() { return root.end(); } - const typename set::iterator begin() const { return root.begin(); } - const typename set::iterator end() const { return root.end(); } + auto begin() -> typename set::iterator { return root.begin(); } + auto end() -> typename set::iterator { return root.end(); } + + auto begin() const -> const typename set::iterator { return root.begin(); } + auto end() const -> const typename set::iterator { return root.end(); } protected: set root; }; template struct bimap { - maybe find(const T& key) const { return tmap.find(key); } - maybe 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 { return tmap.find(key); } + auto find(const U& key) const -> maybe { 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::node_t>::iterator begin() { return tmap.begin(); } - typename set::node_t>::iterator end() { return tmap.end(); } - const typename set::node_t>::iterator begin() const { return tmap.begin(); } - const typename set::node_t>::iterator end() const { return tmap.end(); } + auto begin() -> typename set::node_t>::iterator { return tmap.begin(); } + auto end() -> typename set::node_t>::iterator { return tmap.end(); } + + auto begin() const -> const typename set::node_t>::iterator { return tmap.begin(); } + auto end() const -> const typename set::node_t>::iterator { return tmap.end(); } protected: map tmap; diff --git a/nall/matrix.hpp b/nall/matrix.hpp index 991c7e68..a1705335 100644 --- a/nall/matrix.hpp +++ b/nall/matrix.hpp @@ -5,7 +5,7 @@ namespace nall { namespace Matrix { -template inline void Multiply(T* output, const T* xdata, unsigned xrows, unsigned xcols, const T* ydata, unsigned yrows, unsigned ycols) { +template 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 inline void Multiply(T* output, const T* xdata, unsigned xr } } -template inline vector Multiply(const T* xdata, unsigned xrows, unsigned xcols, const T* ydata, unsigned yrows, unsigned ycols) { +template inline auto Multiply(const T* xdata, unsigned xrows, unsigned xcols, const T* ydata, unsigned yrows, unsigned ycols) -> vector { vector output; output.resize(xrows * ycols); Multiply(output.data(), xdata, xrows, xcols, ydata, yrows, ycols); diff --git a/nall/method.hpp b/nall/method.hpp index c79eab0a..36a203fe 100644 --- a/nall/method.hpp +++ b/nall/method.hpp @@ -20,7 +20,7 @@ template struct method { template struct chain { chain(T& self, const F& f) : self(self), f(f) {} template auto operator()(P&&... p) -> T& { - return f(self, std::forward

(p)...), self; + return f(self, forward

(p)...), self; } private: T& self; @@ -30,7 +30,7 @@ template struct method { template struct const_chain { const_chain(const T& self, const F& f) : self(self), f(f) {} template auto operator()(P&&... p) const -> const T& { - return f(self, std::forward

(p)...), self; + return f(self, forward

(p)...), self; } private: const T& self; @@ -44,13 +44,13 @@ template struct method { auto operator[](const F& f) const -> const_chain { return const_chain((const T&)*this, f); } template>> - auto operator()(const F& f, P&&... p) -> decltype(f((T&)*this, std::forward

(p)...)) { - return f((T&)*this, std::forward

(p)...); + auto operator()(const F& f, P&&... p) -> decltype(f((T&)*this, forward

(p)...)) { + return f((T&)*this, forward

(p)...); } template>> - auto operator()(const F& f, P&&... p) const -> decltype(f((const T&)*this, std::forward

(p)...)) { - return f((const T&)*this, std::forward

(p)...); + auto operator()(const F& f, P&&... p) const -> decltype(f((const T&)*this, forward

(p)...)) { + return f((const T&)*this, forward

(p)...); } }; diff --git a/nall/mosaic/context.hpp b/nall/mosaic/context.hpp index 97719ffa..d4ca1932 100644 --- a/nall/mosaic/context.hpp +++ b/nall/mosaic/context.hpp @@ -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]); diff --git a/nall/nall.hpp b/nall/nall.hpp index be7017f9..86566576 100644 --- a/nall/nall.hpp +++ b/nall/nall.hpp @@ -28,7 +28,6 @@ #include #include #include -#include #include #include #include diff --git a/nall/odbc.hpp b/nall/odbc.hpp deleted file mode 100644 index cfcd5c0e..00000000 --- a/nall/odbc.hpp +++ /dev/null @@ -1,153 +0,0 @@ -#ifndef NALL_ODBC_HPP -#define NALL_ODBC_HPP - -//minimal wrapper for core ODBC v3 API -//requires Windows or unixODBC - -#include -#include - -#include -#include -#include - -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 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 -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 diff --git a/nall/posix/shared-memory.hpp b/nall/posix/shared-memory.hpp index 549308d6..8a50294e 100644 --- a/nall/posix/shared-memory.hpp +++ b/nall/posix/shared-memory.hpp @@ -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); diff --git a/nall/priority-queue.hpp b/nall/priority-queue.hpp index b1576993..35eaf1d3 100644 --- a/nall/priority-queue.hpp +++ b/nall/priority-queue.hpp @@ -8,7 +8,7 @@ namespace nall { -template void priority_queue_nocallback(type_t) {} +template 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 void priority_queue_nocallback(type_t) {} //O(log n) append (enqueue) //O(log n) remove (dequeue) template struct priority_queue { - inline void tick(unsigned ticks) { + priority_queue(unsigned size, function callback = &priority_queue_nocallback) : 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::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 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 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 struct priority_queue { } } - priority_queue(unsigned size, function callback = &priority_queue_nocallback) - : 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 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::max() >> 1); } }; diff --git a/nall/property.hpp b/nall/property.hpp index 575acba1..17e9352c 100644 --- a/nall/property.hpp +++ b/nall/property.hpp @@ -5,36 +5,36 @@ namespace nall { template struct property { template 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 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 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; }; }; diff --git a/nall/random.hpp b/nall/random.hpp index bd443f40..7cfce97b 100644 --- a/nall/random.hpp +++ b/nall/random.hpp @@ -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(); } diff --git a/nall/range.hpp b/nall/range.hpp index 54efbb25..159a30d2 100644 --- a/nall/range.hpp +++ b/nall/range.hpp @@ -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 inline range_t range(const vector& container) { +template inline auto range(const vector& container) { return range_t{0, (signed)container.size(), 1}; } diff --git a/nall/serial.hpp b/nall/serial.hpp index 14d2b321..6bdc810f 100644 --- a/nall/serial.hpp +++ b/nall/serial.hpp @@ -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; diff --git a/nall/serializer.hpp b/nall/serializer.hpp index 5b2c8ef6..ce4171c4 100644 --- a/nall/serializer.hpp +++ b/nall/serializer.hpp @@ -23,31 +23,31 @@ struct serializer; template struct has_serialize { - template static char test(decltype(std::declval().serialize(std::declval()))*); - template static long test(...); + template static auto test(decltype(std::declval().serialize(std::declval()))*) -> char; + template static auto test(...) -> long; static const bool value = sizeof(test(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 serializer& floatingpoint(T& value) { + template 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 serializer& integer(T& value) { + template auto integer(T& value) -> serializer& { enum { size = std::is_same::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 serializer& array(T (&array)[N]) { + template auto array(T (&array)[N]) -> serializer& { for(unsigned n = 0; n < N; n++) operator()(array[n]); return *this; } - template serializer& array(T array, unsigned size) { + template auto array(T array, unsigned size) -> serializer& { for(unsigned n = 0; n < size; n++) operator()(array[n]); return *this; } - template serializer& operator()(T& value, typename std::enable_if::value>::type* = 0) { value.serialize(*this); return *this; } - template serializer& operator()(T& value, typename std::enable_if::value>::type* = 0) { return integer(value); } - template serializer& operator()(T& value, typename std::enable_if::value>::type* = 0) { return floatingpoint(value); } - template serializer& operator()(T& value, typename std::enable_if::value>::type* = 0) { return array(value); } - template serializer& operator()(T& value, unsigned size, typename std::enable_if::value>::type* = 0) { return array(value, size); } + template auto operator()(T& value, typename std::enable_if::value>::type* = 0) -> serializer& { value.serialize(*this); return *this; } + template auto operator()(T& value, typename std::enable_if::value>::type* = 0) -> serializer& { return integer(value); } + template auto operator()(T& value, typename std::enable_if::value>::type* = 0) -> serializer& { return floatingpoint(value); } + template auto operator()(T& value, typename std::enable_if::value>::type* = 0) -> serializer& { return array(value); } + template auto operator()(T& value, unsigned size, typename std::enable_if::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; diff --git a/nall/set.hpp b/nall/set.hpp index d463296d..14121c5d 100644 --- a/nall/set.hpp +++ b/nall/set.hpp @@ -29,33 +29,33 @@ template 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 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 find(const T& value) { + auto find(const T& value) -> maybe { if(node_t* node = find(root, value)) return node->value; return nothing; } - maybe find(const T& value) const { + auto find(const T& value) const -> maybe { if(node_t* node = find(root, value)) return node->value; return nothing; } - maybe insert(const T& value) { + auto insert(const T& value) -> maybe { unsigned count = size(); node_t* v = insert(root, value); root->red = 0; @@ -63,13 +63,13 @@ template struct set { return v->value; } - template bool insert(const T& value, Args&&... args) { + template auto insert(const T& value, Args&&... args) -> bool { bool result = insert(value); - insert(std::forward(args)...) | result; + insert(forward(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 struct set { return size() < count; } - template bool remove(const T& value, Args&&... args) { + template auto remove(const T& value, Args&&... args) -> bool { bool result = remove(value); - return remove(std::forward(args)...) | result; + return remove(forward(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 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) { diff --git a/nall/smtp.hpp b/nall/smtp.hpp index 54197e9a..17d78624 100644 --- a/nall/smtp.hpp +++ b/nall/smtp.hpp @@ -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& 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& 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 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 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& contacts) { +auto SMTP::contacts(const vector& 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); } diff --git a/nall/sort.hpp b/nall/sort.hpp index 5517dd3a..1eaec2fe 100644 --- a/nall/sort.hpp +++ b/nall/sort.hpp @@ -20,7 +20,7 @@ namespace nall { -template void sort(T list[], unsigned size, const Comparator& lessthan) { +template 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 void sort(T list[], unsigned size, con delete[] buffer; } -template void sort(T list[], unsigned size) { +template auto sort(T list[], unsigned size) -> void { return sort(list, size, [](const T& l, const T& r) { return l < r; }); } diff --git a/nall/string/atoi.hpp b/nall/string/atoi.hpp index 9af86f16..97e2d91c 100644 --- a/nall/string/atoi.hpp +++ b/nall/string/atoi.hpp @@ -16,6 +16,10 @@ auto string::decimal() const -> uintmax_t { return nall::decimal(data()); } +auto string::real() const -> double { + return nall::real(data()); +} + } #endif diff --git a/nall/string/base.hpp b/nall/string/base.hpp index f531699e..23eecfd7 100644 --- a/nall/string/base.hpp +++ b/nall/string/base.hpp @@ -59,13 +59,13 @@ inline auto ifindFrom(const string& self, signed offset, rstring source) -> mayb //format.hpp template inline auto print(P&&...) -> void; -template inline auto integer(intmax_t value) -> string; -template inline auto decimal(uintmax_t value) -> string; -template inline auto hex(uintmax_t value) -> string; -template inline auto octal(uintmax_t value) -> string; -template inline auto binary(uintmax_t value) -> string; -template inline auto pointer(const T* value) -> string; -template 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 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 inline auto _replace(string& self, rstring from, rstring to) -> string&; -template inline auto replace(string& self, rstring from, rstring to) -> string&; -template inline auto ireplace(string& self, rstring from, rstring to) -> string&; -template inline auto qreplace(string& self, rstring from, rstring to) -> string&; -template inline auto iqreplace(string& self, rstring from, rstring to) -> string&; +template 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 inline auto _split(lstring& self, rstring source, rstring find) -> lstring&; -template inline auto split(string& self, rstring key) -> lstring; -template inline auto isplit(string& self, rstring key) -> lstring; -template inline auto qsplit(string& self, rstring key) -> lstring; -template inline auto iqsplit(string& self, rstring key) -> lstring; +template 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 string(T&& s, P&&... p) : string() { append(std::forward(s), std::forward

(p)...); } + template string(T&& s, P&&... p) : string() { append(forward(s), forward

(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 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 auto assign(P&&... p) -> type& { return nall::assign(*this, std::forward

(p)...); } - template auto append(P&&... p) -> type& { return nall::append(*this, std::forward

(p)...); } + template auto assign(P&&... p) -> type& { return nall::assign(*this, forward

(p)...); } + template auto append(P&&... p) -> type& { return nall::append(*this, forward

(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 auto replace(rstring from, rstring to) -> type& { return nall::_replace(*this, from, to); } - template auto ireplace(rstring from, rstring to) -> type& { return nall::_replace(*this, from, to); } - template auto qreplace(rstring from, rstring to) -> type& { return nall::_replace(*this, from, to); } - template auto iqreplace(rstring from, rstring to) -> type& { return nall::_replace(*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 inline auto split(rstring key) const -> lstring; - template inline auto isplit(rstring key) const -> lstring; - template inline auto qsplit(rstring key) const -> lstring; - template 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 { lstring(const lstring& source) { vector::operator=(source); } lstring(lstring& source) { vector::operator=(source); } lstring(lstring&& source) { vector::operator=(std::move(source)); } - template lstring(P&&... p) { append(std::forward

(p)...); } + template lstring(P&&... p) { append(forward

(p)...); } //list.hpp inline auto operator==(const lstring&) const -> bool; @@ -364,17 +365,17 @@ struct lstring : vector { //================= //list.hpp - template auto append(P&&... p) -> type& { return nall::append(*this, std::forward

(p)...); } + template auto append(P&&... p) -> type& { return nall::append(*this, forward

(p)...); } auto find(const string& source) const -> maybe { return nall::find(*this, source); } auto ifind(const string& source) const -> maybe { 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 auto split(rstring source, rstring on) -> type& { return nall::_split(*this, source, on); } - template auto isplit(rstring source, rstring on) -> type& { return nall::_split(*this, source, on); } - template auto qsplit(rstring source, rstring on) -> type& { return nall::_split(*this, source, on); } - template auto iqsplit(rstring source, rstring on) -> type& { return nall::_split(*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 { using type = format; - template format(P&&... p) { reserve(sizeof...(p)); append(std::forward

(p)...); } - template auto append(P&&... p) -> type& { return nall::append(*this, std::forward

(p)...); } + template format(P&&... p) { reserve(sizeof...(p)); append(forward

(p)...); } + template auto append(P&&... p) -> type& { return nall::append(*this, forward

(p)...); } }; } diff --git a/nall/string/datetime.hpp b/nall/string/datetime.hpp index bf27007c..95016026 100644 --- a/nall/string/datetime.hpp +++ b/nall/string/datetime.hpp @@ -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) }; } diff --git a/nall/string/eval/evaluator.hpp b/nall/string/eval/evaluator.hpp index 5e77ff7f..da6023b1 100644 --- a/nall/string/eval/evaluator.hpp +++ b/nall/string/eval/evaluator.hpp @@ -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 diff --git a/nall/string/format.hpp b/nall/string/format.hpp index 827850c5..739895d2 100644 --- a/nall/string/format.hpp +++ b/nall/string/format.hpp @@ -73,7 +73,7 @@ template auto print(P&&... p) -> void { fputs(s.data(), stdout); } -template 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 auto integer(intmax_t value) -> string return buffer; } -template 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 auto decimal(uintmax_t value) -> string return buffer; } -template 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 auto hex(uintmax_t value) -> string { return buffer; } -template 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 auto octal(uintmax_t value) -> string { return buffer; } -template 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 auto binary(uintmax_t value) -> string return buffer; } -template auto pointer(const T* value) -> string { +template auto pointer(const T* value, long precision) -> string { if(value == nullptr) return "(null)"; - return {"0x", hex((uintptr_t)value)}; + return {"0x", hex((uintptr_t)value, precision)}; } -template auto pointer(uintptr_t value) -> string { +auto pointer(uintptr_t value, long precision) -> string { if(value == 0) return "(null)"; - return {"0x", hex(value)}; + return {"0x", hex(value, precision)}; } auto real(long double value) -> string { diff --git a/nall/string/hash.hpp b/nall/string/hash.hpp index 98084ec4..52c3a825 100644 --- a/nall/string/hash.hpp +++ b/nall/string/hash.hpp @@ -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; } } diff --git a/nall/string/markup/bml.hpp b/nall/string/markup/bml.hpp index 3df074ed..17d62b08 100644 --- a/nall/string/markup/bml.hpp +++ b/nall/string/markup/bml.hpp @@ -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 diff --git a/nall/string/markup/find.hpp b/nall/string/markup/find.hpp index e0080cb1..ca8e7a93 100644 --- a/nall/string/markup/find.hpp +++ b/nall/string/markup/find.hpp @@ -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 { 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 { } if(name.match("*(*)")) { - auto p = name.rtrim(")").split<1>("("); + auto p = name.rtrim(")", 1L).split("(", 1L); name = p(0); rule = p(1); } diff --git a/nall/string/replace.hpp b/nall/string/replace.hpp index f27b06ad..96cd2537 100644 --- a/nall/string/replace.hpp +++ b/nall/string/replace.hpp @@ -2,9 +2,9 @@ namespace nall { -template -auto _replace(string& self, rstring from, rstring to) -> string& { - if(Limit == 0 || from.size() == 0) return self; +template +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(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 auto replace(string& self, rstring from, rstring to) -> string& { return _replace(self, from, to); } -template auto ireplace(string& self, rstring from, rstring to) -> string& { return _replace(self, from, to); } -template auto qreplace(string& self, rstring from, rstring to) -> string& { return _replace(self, from, to); } -template auto iqreplace(string& self, rstring from, rstring to) -> string& { return _replace(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); } }; diff --git a/nall/string/split.hpp b/nall/string/split.hpp index f5c5e516..ee4bc845 100644 --- a/nall/string/split.hpp +++ b/nall/string/split.hpp @@ -2,9 +2,9 @@ namespace nall { -template auto _split(lstring& self, rstring source, rstring find) -> lstring& { +template 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 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(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 auto _split(lstring& sel return self; } -template auto split(string& self, rstring on) -> lstring { return lstring().split(self, on); } -template auto isplit(string& self, rstring on) -> lstring { return lstring().isplit(self, on); } -template auto qsplit(string& self, rstring on) -> lstring { return lstring().qsplit(self, on); } -template auto iqsplit(string& self, rstring on) -> lstring { return lstring().iqsplit(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 auto string::split(rstring on) const -> lstring { return lstring().split(*this, on); } -template auto string::isplit(rstring on) const -> lstring { return lstring().isplit(*this, on); } -template auto string::qsplit(rstring on) const -> lstring { return lstring().qsplit(*this, on); } -template auto string::iqsplit(rstring on) const -> lstring { return lstring().iqsplit(*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); } } diff --git a/nall/string/transform/cml.hpp b/nall/string/transform/cml.hpp index 17a1b266..3557afb6 100644 --- a/nall/string/transform/cml.hpp +++ b/nall/string/transform/cml.hpp @@ -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& 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 reader; + } settings; + struct State { string output; } state; @@ -22,22 +29,25 @@ private: }; vector 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; diff --git a/nall/string/transform/dml.hpp b/nall/string/transform/dml.hpp index 0c5e94d5..b027233d 100644 --- a/nall/string/transform/dml.hpp +++ b/nall/string/transform/dml.hpp @@ -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& 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 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("\n"); + for(auto& block : blocks) parseBlock(block, pathname, depth); + if(settings.sectioned && state.sections && depth == 0) state.output.append("\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("")) { + string filename{pathname, block.trim("", 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("\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(""); state.output.append("

"); } - 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("
", data); for(auto& line : lines) { if(!line.beginsWith("# ")) continue; - state.output.append("", line.ltrim("# "), ""); + state.output.append("", line.ltrim("# ", 1L), ""); } state.output.append("
\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("