mirror of
https://github.com/bsnes-emu/bsnes.git
synced 2025-09-03 03:33:16 +02:00
First version split into asnes and bsnes.
This commit is contained in:
141
nall/string/base.hpp
Executable file
141
nall/string/base.hpp
Executable file
@@ -0,0 +1,141 @@
|
||||
#ifndef NALL_STRING_BASE_HPP
|
||||
#define NALL_STRING_BASE_HPP
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <nall/concept.hpp>
|
||||
#include <nall/stdint.hpp>
|
||||
#include <nall/utf8.hpp>
|
||||
#include <nall/vector.hpp>
|
||||
|
||||
namespace nall {
|
||||
class string;
|
||||
template<typename T> inline string to_string(T);
|
||||
|
||||
class string {
|
||||
public:
|
||||
inline void reserve(unsigned);
|
||||
inline unsigned length() const;
|
||||
|
||||
inline string& assign(const char*);
|
||||
inline string& append(const char*);
|
||||
inline string& append(bool);
|
||||
inline string& append(signed int value);
|
||||
inline string& append(unsigned int value);
|
||||
inline string& append(double value);
|
||||
|
||||
template<typename T> inline string& operator= (T value);
|
||||
template<typename T> inline string& operator<<(T value);
|
||||
|
||||
inline operator const char*() const;
|
||||
inline char* operator()();
|
||||
inline char& operator[](int);
|
||||
|
||||
inline bool operator==(const char*) const;
|
||||
inline bool operator!=(const char*) const;
|
||||
inline bool operator< (const char*) const;
|
||||
inline bool operator<=(const char*) const;
|
||||
inline bool operator> (const char*) const;
|
||||
inline bool operator>=(const char*) const;
|
||||
|
||||
inline string& operator=(const string&);
|
||||
inline string& operator=(string&&);
|
||||
|
||||
template<typename... Args> inline string(Args... args);
|
||||
inline string(const string&);
|
||||
inline string(string&&);
|
||||
inline ~string();
|
||||
|
||||
inline bool readfile(const char*);
|
||||
inline string& replace (const char*, const char*);
|
||||
inline string& qreplace(const char*, const char*);
|
||||
|
||||
inline string& lower();
|
||||
inline string& upper();
|
||||
inline string& transform(const char *before, const char *after);
|
||||
inline string& ltrim(const char *key = " ");
|
||||
inline string& rtrim(const char *key = " ");
|
||||
inline string& trim (const char *key = " ");
|
||||
inline string& ltrim_once(const char *key = " ");
|
||||
inline string& rtrim_once(const char *key = " ");
|
||||
inline string& trim_once (const char *key = " ");
|
||||
|
||||
protected:
|
||||
char *data;
|
||||
unsigned size;
|
||||
|
||||
#if defined(QSTRING_H)
|
||||
public:
|
||||
inline operator QString() const;
|
||||
#endif
|
||||
};
|
||||
|
||||
class lstring : public linear_vector<string> {
|
||||
public:
|
||||
template<typename T> inline lstring& operator<<(T value);
|
||||
|
||||
inline optional<unsigned> find(const char*);
|
||||
inline void split (const char*, const char*, unsigned = 0);
|
||||
inline void qsplit(const char*, const char*, unsigned = 0);
|
||||
|
||||
lstring();
|
||||
lstring(std::initializer_list<string>);
|
||||
};
|
||||
|
||||
//compare.hpp
|
||||
inline char chrlower(char c);
|
||||
inline char chrupper(char c);
|
||||
inline int stricmp(const char *dest, const char *src);
|
||||
inline bool strbegin (const char *str, const char *key);
|
||||
inline bool stribegin(const char *str, const char *key);
|
||||
inline bool strend (const char *str, const char *key);
|
||||
inline bool striend(const char *str, const char *key);
|
||||
|
||||
//convert.hpp
|
||||
inline char* strlower(char *str);
|
||||
inline char* strupper(char *str);
|
||||
inline char* strtr(char *dest, const char *before, const char *after);
|
||||
inline uintmax_t strhex (const char *str);
|
||||
inline intmax_t strsigned (const char *str);
|
||||
inline uintmax_t strunsigned(const char *str);
|
||||
inline uintmax_t strbin (const char *str);
|
||||
inline double strdouble (const char *str);
|
||||
|
||||
//match.hpp
|
||||
inline bool match(const char *pattern, const char *str);
|
||||
|
||||
//math.hpp
|
||||
inline bool strint (const char *str, int &result);
|
||||
inline bool strmath(const char *str, int &result);
|
||||
|
||||
//strl.hpp
|
||||
inline unsigned strlcpy(char *dest, const char *src, unsigned length);
|
||||
inline unsigned strlcat(char *dest, const char *src, unsigned length);
|
||||
|
||||
//trim.hpp
|
||||
inline char* ltrim(char *str, const char *key = " ");
|
||||
inline char* rtrim(char *str, const char *key = " ");
|
||||
inline char* trim (char *str, const char *key = " ");
|
||||
inline char* ltrim_once(char *str, const char *key = " ");
|
||||
inline char* rtrim_once(char *str, const char *key = " ");
|
||||
inline char* trim_once (char *str, const char *key = " ");
|
||||
|
||||
//utility.hpp
|
||||
inline unsigned strlcpy(string &dest, const char *src, unsigned length);
|
||||
inline unsigned strlcat(string &dest, const char *src, unsigned length);
|
||||
inline string substr(const char *src, unsigned start = 0, unsigned length = 0);
|
||||
inline string& strtr(string &dest, const char *before, const char *after);
|
||||
template<unsigned length = 0, char padding = '0'> inline string strhex(uintmax_t value);
|
||||
template<unsigned length = 0, char padding = '0'> inline string strsigned(intmax_t value);
|
||||
template<unsigned length = 0, char padding = '0'> inline string strunsigned(uintmax_t value);
|
||||
template<unsigned length = 0, char padding = '0'> inline string strbin(uintmax_t value);
|
||||
inline unsigned strdouble(char *str, double value);
|
||||
inline string strdouble(double value);
|
||||
|
||||
//variadic.hpp
|
||||
template<typename... Args> inline void print(Args... args);
|
||||
};
|
||||
|
||||
#endif
|
75
nall/string/bsv.hpp
Executable file
75
nall/string/bsv.hpp
Executable file
@@ -0,0 +1,75 @@
|
||||
#ifndef NALL_STRING_BSV_HPP
|
||||
#define NALL_STRING_BSV_HPP
|
||||
|
||||
//BSV parser
|
||||
//version 0.01
|
||||
|
||||
namespace nall {
|
||||
|
||||
inline string bsv_decode(const char *input) {
|
||||
string output;
|
||||
unsigned offset = 0;
|
||||
while(*input) {
|
||||
//illegal characters
|
||||
if(*input == '}' ) return "";
|
||||
if(*input == '\r') return "";
|
||||
if(*input == '\n') return "";
|
||||
|
||||
//normal characters
|
||||
if(*input != '{') { output[offset++] = *input++; continue; }
|
||||
|
||||
//entities
|
||||
if(strbegin(input, "{lf}")) { output[offset++] = '\n'; input += 4; continue; }
|
||||
if(strbegin(input, "{lb}")) { output[offset++] = '{'; input += 4; continue; }
|
||||
if(strbegin(input, "{rb}")) { output[offset++] = '}'; input += 4; continue; }
|
||||
|
||||
//illegal entities
|
||||
return "";
|
||||
}
|
||||
output[offset] = 0;
|
||||
return output;
|
||||
}
|
||||
|
||||
inline string bsv_encode(const char *input) {
|
||||
string output;
|
||||
unsigned offset = 0;
|
||||
while(*input) {
|
||||
//illegal characters
|
||||
if(*input == '\r') return "";
|
||||
|
||||
if(*input == '\n') {
|
||||
output[offset++] = '{';
|
||||
output[offset++] = 'l';
|
||||
output[offset++] = 'f';
|
||||
output[offset++] = '}';
|
||||
input++;
|
||||
continue;
|
||||
}
|
||||
|
||||
if(*input == '{') {
|
||||
output[offset++] = '{';
|
||||
output[offset++] = 'l';
|
||||
output[offset++] = 'b';
|
||||
output[offset++] = '}';
|
||||
input++;
|
||||
continue;
|
||||
}
|
||||
|
||||
if(*input == '}') {
|
||||
output[offset++] = '{';
|
||||
output[offset++] = 'r';
|
||||
output[offset++] = 'b';
|
||||
output[offset++] = '}';
|
||||
input++;
|
||||
continue;
|
||||
}
|
||||
|
||||
output[offset++] = *input++;
|
||||
}
|
||||
output[offset] = 0;
|
||||
return output;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
32
nall/string/cast.hpp
Executable file
32
nall/string/cast.hpp
Executable file
@@ -0,0 +1,32 @@
|
||||
#ifndef NALL_STRING_CAST_HPP
|
||||
#define NALL_STRING_CAST_HPP
|
||||
|
||||
namespace nall {
|
||||
|
||||
//this is needed, as C++0x does not support explicit template specialization inside classes
|
||||
template<> inline string to_string<bool> (bool v) { return v ? "true" : "false"; }
|
||||
template<> inline string to_string<signed int> (signed int v) { return strsigned(v); }
|
||||
template<> inline string to_string<unsigned int> (unsigned int v) { return strunsigned(v); }
|
||||
template<> inline string to_string<double> (double v) { return strdouble(v); }
|
||||
template<> inline string to_string<char*> (char *v) { return v; }
|
||||
template<> inline string to_string<const char*> (const char *v) { return v; }
|
||||
template<> inline string to_string<string> (string v) { return v; }
|
||||
template<> inline string to_string<const string&>(const string &v) { return v; }
|
||||
|
||||
template<typename T> string& string::operator= (T value) { return assign(to_string<T>(value)); }
|
||||
template<typename T> string& string::operator<<(T value) { return append(to_string<T>(value)); }
|
||||
|
||||
template<typename T> lstring& lstring::operator<<(T value) {
|
||||
operator[](size()).assign(to_string<T>(value));
|
||||
return *this;
|
||||
}
|
||||
|
||||
#if defined(QSTRING_H)
|
||||
template<> inline string to_string<QString>(QString v) { return v.toUtf8().constData(); }
|
||||
template<> inline string to_string<const QString&>(const QString &v) { return v.toUtf8().constData(); }
|
||||
string::operator QString() const { return QString::fromUtf8(*this); }
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
#endif
|
72
nall/string/compare.hpp
Executable file
72
nall/string/compare.hpp
Executable file
@@ -0,0 +1,72 @@
|
||||
#ifndef NALL_STRING_COMPARE_HPP
|
||||
#define NALL_STRING_COMPARE_HPP
|
||||
|
||||
namespace nall {
|
||||
|
||||
char chrlower(char c) {
|
||||
return (c >= 'A' && c <= 'Z') ? c + ('a' - 'A') : c;
|
||||
}
|
||||
|
||||
char chrupper(char c) {
|
||||
return (c >= 'a' && c <= 'z') ? c - ('a' - 'A') : c;
|
||||
}
|
||||
|
||||
int stricmp(const char *dest, const char *src) {
|
||||
while(*dest) {
|
||||
if(chrlower(*dest) != chrlower(*src)) break;
|
||||
dest++;
|
||||
src++;
|
||||
}
|
||||
|
||||
return (int)chrlower(*dest) - (int)chrlower(*src);
|
||||
}
|
||||
|
||||
bool strbegin(const char *str, const char *key) {
|
||||
int i, ssl = strlen(str), ksl = strlen(key);
|
||||
|
||||
if(ksl > ssl) return false;
|
||||
return (!memcmp(str, key, ksl));
|
||||
}
|
||||
|
||||
bool stribegin(const char *str, const char *key) {
|
||||
int ssl = strlen(str), ksl = strlen(key);
|
||||
|
||||
if(ksl > ssl) return false;
|
||||
for(int i = 0; i < ksl; i++) {
|
||||
if(str[i] >= 'A' && str[i] <= 'Z') {
|
||||
if(str[i] != key[i] && str[i]+0x20 != key[i])return false;
|
||||
} else if(str[i] >= 'a' && str[i] <= 'z') {
|
||||
if(str[i] != key[i] && str[i]-0x20 != key[i])return false;
|
||||
} else {
|
||||
if(str[i] != key[i])return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool strend(const char *str, const char *key) {
|
||||
int ssl = strlen(str), ksl = strlen(key);
|
||||
|
||||
if(ksl > ssl) return false;
|
||||
return (!memcmp(str + ssl - ksl, key, ksl));
|
||||
}
|
||||
|
||||
bool striend(const char *str, const char *key) {
|
||||
int ssl = strlen(str), ksl = strlen(key);
|
||||
|
||||
if(ksl > ssl) return false;
|
||||
for(int i = ssl - ksl, z = 0; i < ssl; i++, z++) {
|
||||
if(str[i] >= 'A' && str[i] <= 'Z') {
|
||||
if(str[i] != key[z] && str[i]+0x20 != key[z])return false;
|
||||
} else if(str[i] >= 'a' && str[i] <= 'z') {
|
||||
if(str[i] != key[z] && str[i]-0x20 != key[z])return false;
|
||||
} else {
|
||||
if(str[i] != key[z])return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
157
nall/string/convert.hpp
Executable file
157
nall/string/convert.hpp
Executable file
@@ -0,0 +1,157 @@
|
||||
#ifndef NALL_STRING_CONVERT_HPP
|
||||
#define NALL_STRING_CONVERT_HPP
|
||||
|
||||
namespace nall {
|
||||
|
||||
char* strlower(char *str) {
|
||||
if(!str) return 0;
|
||||
int i = 0;
|
||||
while(str[i]) {
|
||||
str[i] = chrlower(str[i]);
|
||||
i++;
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
char* strupper(char *str) {
|
||||
if(!str) return 0;
|
||||
int i = 0;
|
||||
while(str[i]) {
|
||||
str[i] = chrupper(str[i]);
|
||||
i++;
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
char* strtr(char *dest, const char *before, const char *after) {
|
||||
if(!dest || !before || !after) return dest;
|
||||
int sl = strlen(dest), bsl = strlen(before), asl = strlen(after);
|
||||
|
||||
if(bsl != asl || bsl == 0) return dest; //patterns must be the same length for 1:1 replace
|
||||
for(unsigned i = 0; i < sl; i++) {
|
||||
for(unsigned l = 0; l < bsl; l++) {
|
||||
if(dest[i] == before[l]) {
|
||||
dest[i] = after[l];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return dest;
|
||||
}
|
||||
|
||||
string& string::lower() { nall::strlower(data); return *this; }
|
||||
string& string::upper() { nall::strupper(data); return *this; }
|
||||
string& string::transform(const char *before, const char *after) { nall::strtr(data, before, after); return *this; }
|
||||
|
||||
uintmax_t strhex(const char *str) {
|
||||
if(!str) return 0;
|
||||
uintmax_t result = 0;
|
||||
|
||||
//skip hex identifiers 0x and $, if present
|
||||
if(*str == '0' && (*(str + 1) == 'X' || *(str + 1) == 'x')) str += 2;
|
||||
else if(*str == '$') str++;
|
||||
|
||||
while(*str) {
|
||||
uint8_t x = *str++;
|
||||
if(x >= '0' && x <= '9') x -= '0';
|
||||
else if(x >= 'A' && x <= 'F') x -= 'A' - 10;
|
||||
else if(x >= 'a' && x <= 'f') x -= 'a' - 10;
|
||||
else break; //stop at first invalid character
|
||||
result = result * 16 + x;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
intmax_t strsigned(const char *str) {
|
||||
if(!str) return 0;
|
||||
intmax_t result = 0;
|
||||
bool negate = false;
|
||||
|
||||
//check for negation
|
||||
if(*str == '-') {
|
||||
negate = true;
|
||||
str++;
|
||||
}
|
||||
|
||||
while(*str) {
|
||||
uint8_t x = *str++;
|
||||
if(x >= '0' && x <= '9') x -= '0';
|
||||
else break; //stop at first invalid character
|
||||
result = result * 10 + x;
|
||||
}
|
||||
|
||||
return !negate ? result : -result;
|
||||
}
|
||||
|
||||
uintmax_t strunsigned(const char *str) {
|
||||
if(!str) return 0;
|
||||
uintmax_t result = 0;
|
||||
|
||||
while(*str) {
|
||||
uint8_t x = *str++;
|
||||
if(x >= '0' && x <= '9') x -= '0';
|
||||
else break; //stop at first invalid character
|
||||
result = result * 10 + x;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
uintmax_t strbin(const char *str) {
|
||||
if(!str) return 0;
|
||||
uintmax_t result = 0;
|
||||
|
||||
//skip bin identifiers 0b and %, if present
|
||||
if(*str == '0' && (*(str + 1) == 'B' || *(str + 1) == 'b')) str += 2;
|
||||
else if(*str == '%') str++;
|
||||
|
||||
while(*str) {
|
||||
uint8_t x = *str++;
|
||||
if(x == '0' || x == '1') x -= '0';
|
||||
else break; //stop at first invalid character
|
||||
result = result * 2 + x;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
double strdouble(const char *str) {
|
||||
if(!str) return 0.0;
|
||||
bool negate = false;
|
||||
|
||||
//check for negation
|
||||
if(*str == '-') {
|
||||
negate = true;
|
||||
str++;
|
||||
}
|
||||
|
||||
intmax_t result_integral = 0;
|
||||
while(*str) {
|
||||
uint8_t x = *str++;
|
||||
if(x >= '0' && x <= '9') x -= '0';
|
||||
else if(x == '.' || x == ',') break; //break loop and read fractional part
|
||||
else return (double)result_integral; //invalid value, assume no fractional part
|
||||
result_integral = result_integral * 10 + x;
|
||||
}
|
||||
|
||||
intmax_t result_fractional = 0;
|
||||
while(*str) {
|
||||
uint8_t x = *str++;
|
||||
if(x >= '0' && x <= '9') x -= '0';
|
||||
else break; //stop at first invalid character
|
||||
result_fractional = result_fractional * 10 + x;
|
||||
}
|
||||
|
||||
//calculate fractional portion
|
||||
double result = (double)result_fractional;
|
||||
while((uintmax_t)result > 0) result /= 10.0;
|
||||
result += (double)result_integral;
|
||||
|
||||
return !negate ? result : -result;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
143
nall/string/core.hpp
Executable file
143
nall/string/core.hpp
Executable file
@@ -0,0 +1,143 @@
|
||||
#ifndef NALL_STRING_CORE_HPP
|
||||
#define NALL_STRING_CORE_HPP
|
||||
|
||||
namespace nall {
|
||||
|
||||
void string::reserve(unsigned size_) {
|
||||
if(size_ > size) {
|
||||
size = size_;
|
||||
data = (char*)realloc(data, size + 1);
|
||||
data[size] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
unsigned string::length() const {
|
||||
return strlen(data);
|
||||
}
|
||||
|
||||
string& string::assign(const char *s) {
|
||||
unsigned length = strlen(s);
|
||||
reserve(length);
|
||||
strcpy(data, s);
|
||||
return *this;
|
||||
}
|
||||
|
||||
string& string::append(const char *s) {
|
||||
unsigned length = strlen(data) + strlen(s);
|
||||
reserve(length);
|
||||
strcat(data, s);
|
||||
return *this;
|
||||
}
|
||||
|
||||
string& string::append(bool value) { append(value ? "true" : "false"); return *this; }
|
||||
string& string::append(signed int value) { append(strsigned(value)); return *this; }
|
||||
string& string::append(unsigned int value) { append(strunsigned(value)); return *this; }
|
||||
string& string::append(double value) { append(strdouble(value)); return *this; }
|
||||
|
||||
string::operator const char*() const {
|
||||
return data;
|
||||
}
|
||||
|
||||
char* string::operator()() {
|
||||
return data;
|
||||
}
|
||||
|
||||
char& string::operator[](int index) {
|
||||
reserve(index);
|
||||
return data[index];
|
||||
}
|
||||
|
||||
bool string::operator==(const char *str) const { return strcmp(data, str) == 0; }
|
||||
bool string::operator!=(const char *str) const { return strcmp(data, str) != 0; }
|
||||
bool string::operator< (const char *str) const { return strcmp(data, str) < 0; }
|
||||
bool string::operator<=(const char *str) const { return strcmp(data, str) <= 0; }
|
||||
bool string::operator> (const char *str) const { return strcmp(data, str) > 0; }
|
||||
bool string::operator>=(const char *str) const { return strcmp(data, str) >= 0; }
|
||||
|
||||
string& string::operator=(const string &value) {
|
||||
assign(value);
|
||||
return *this;
|
||||
}
|
||||
|
||||
string& string::operator=(string &&source) {
|
||||
if(data) free(data);
|
||||
size = source.size;
|
||||
data = source.data;
|
||||
source.data = 0;
|
||||
source.size = 0;
|
||||
return *this;
|
||||
}
|
||||
|
||||
static void istring(string &output) {
|
||||
}
|
||||
|
||||
template<typename T, typename... Args>
|
||||
static void istring(string &output, T value, Args... args) {
|
||||
output.append(value);
|
||||
istring(output, args...);
|
||||
}
|
||||
|
||||
template<typename... Args> string::string(Args... args) {
|
||||
size = 64;
|
||||
data = (char*)malloc(size + 1);
|
||||
*data = 0;
|
||||
istring(*this, args...);
|
||||
}
|
||||
|
||||
string::string(const string &value) {
|
||||
size = strlen(value);
|
||||
data = strdup(value);
|
||||
}
|
||||
|
||||
string::string(string &&source) {
|
||||
size = source.size;
|
||||
data = source.data;
|
||||
source.data = 0;
|
||||
}
|
||||
|
||||
string::~string() {
|
||||
if(data) free(data);
|
||||
}
|
||||
|
||||
bool string::readfile(const char *filename) {
|
||||
assign("");
|
||||
|
||||
#if !defined(_WIN32)
|
||||
FILE *fp = fopen(filename, "rb");
|
||||
#else
|
||||
FILE *fp = _wfopen(utf16_t(filename), L"rb");
|
||||
#endif
|
||||
if(!fp) return false;
|
||||
|
||||
fseek(fp, 0, SEEK_END);
|
||||
unsigned size = ftell(fp);
|
||||
rewind(fp);
|
||||
char *fdata = new char[size + 1];
|
||||
unsigned unused = fread(fdata, 1, size, fp);
|
||||
fclose(fp);
|
||||
fdata[size] = 0;
|
||||
assign(fdata);
|
||||
delete[] fdata;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
optional<unsigned> lstring::find(const char *key) {
|
||||
for(unsigned i = 0; i < size(); i++) {
|
||||
if(operator[](i) == key) return { true, i };
|
||||
}
|
||||
return { false, 0 };
|
||||
}
|
||||
|
||||
inline lstring::lstring() {
|
||||
}
|
||||
|
||||
inline lstring::lstring(std::initializer_list<string> list) {
|
||||
for(const string *s = list.begin(); s != list.end(); ++s) {
|
||||
operator<<(*s);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
61
nall/string/filename.hpp
Executable file
61
nall/string/filename.hpp
Executable file
@@ -0,0 +1,61 @@
|
||||
#ifndef NALL_FILENAME_HPP
|
||||
#define NALL_FILENAME_HPP
|
||||
|
||||
namespace nall {
|
||||
|
||||
// "foo/bar.c" -> "foo/", "bar.c" -> "./"
|
||||
inline string dir(char const *name) {
|
||||
string result = name;
|
||||
for(signed i = strlen(result); i >= 0; i--) {
|
||||
if(result[i] == '/' || result[i] == '\\') {
|
||||
result[i + 1] = 0;
|
||||
break;
|
||||
}
|
||||
if(i == 0) result = "./";
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// "foo/bar.c" -> "bar.c"
|
||||
inline string notdir(char const *name) {
|
||||
for(signed i = strlen(name); i >= 0; i--) {
|
||||
if(name[i] == '/' || name[i] == '\\') {
|
||||
name += i + 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
string result = name;
|
||||
return result;
|
||||
}
|
||||
|
||||
// "foo/bar.c" -> "foo/bar"
|
||||
inline string basename(char const *name) {
|
||||
string result = name;
|
||||
for(signed i = strlen(result); i >= 0; i--) {
|
||||
if(result[i] == '/' || result[i] == '\\') {
|
||||
//file has no extension
|
||||
break;
|
||||
}
|
||||
if(result[i] == '.') {
|
||||
result[i] = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// "foo/bar.c" -> "c"
|
||||
inline string extension(char const *name) {
|
||||
for(signed i = strlen(name); i >= 0; i--) {
|
||||
if(name[i] == '.') {
|
||||
name += i + 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
string result = name;
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
76
nall/string/match.hpp
Executable file
76
nall/string/match.hpp
Executable file
@@ -0,0 +1,76 @@
|
||||
#ifndef NALL_STRING_MATCH_HPP
|
||||
#define NALL_STRING_MATCH_HPP
|
||||
|
||||
namespace nall {
|
||||
|
||||
bool match(const char *p, const char *s) {
|
||||
const char *p_ = 0, *s_ = 0;
|
||||
|
||||
for(;;) {
|
||||
if(!*s) {
|
||||
while(*p == '*') p++;
|
||||
return !*p;
|
||||
}
|
||||
|
||||
//wildcard match
|
||||
if(*p == '*') {
|
||||
p_ = p++, s_ = s;
|
||||
continue;
|
||||
}
|
||||
|
||||
//any match
|
||||
if(*p == '?') {
|
||||
p++, s++;
|
||||
continue;
|
||||
}
|
||||
|
||||
//ranged match
|
||||
if(*p == '{') {
|
||||
#define pattern(name_, rule_) \
|
||||
if(strbegin(p, name_)) { \
|
||||
if(rule_) { \
|
||||
p += sizeof(name_) - 1, s++; \
|
||||
continue; \
|
||||
} \
|
||||
goto failure; \
|
||||
}
|
||||
|
||||
pattern("{alpha}", (*s >= 'A' && *s <= 'Z') || (*s >= 'a' && *s <= 'z'))
|
||||
pattern("{alphanumeric}", (*s >= 'A' && *s <= 'Z') || (*s >= 'a' && *s <= 'z') || (*s >= '0' && *s <= '9'))
|
||||
pattern("{binary}", (*s == '0' || *s == '1'))
|
||||
pattern("{hex}", (*s >= '0' && *s <= '9') || (*s >= 'A' && *s <= 'F') || (*s >= 'a' && *s <= 'f'))
|
||||
pattern("{lowercase}", (*s >= 'a' && *s <= 'z'))
|
||||
pattern("{numeric}", (*s >= '0' && *s <= '9'))
|
||||
pattern("{uppercase}", (*s >= 'A' && *s <= 'Z'))
|
||||
pattern("{whitespace}", (*s == ' ' || *s == '\t'))
|
||||
|
||||
#undef pattern
|
||||
goto failure;
|
||||
}
|
||||
|
||||
//reserved character match
|
||||
if(*p == '\\') {
|
||||
p++;
|
||||
//fallthrough
|
||||
}
|
||||
|
||||
//literal match
|
||||
if(*p == *s) {
|
||||
p++, *s++;
|
||||
continue;
|
||||
}
|
||||
|
||||
//attempt wildcard rematch
|
||||
failure:
|
||||
if(p_) {
|
||||
p = p_, s = s_ + 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
164
nall/string/math.hpp
Executable file
164
nall/string/math.hpp
Executable file
@@ -0,0 +1,164 @@
|
||||
#ifndef NALL_STRING_MATH_HPP
|
||||
#define NALL_STRING_MATH_HPP
|
||||
|
||||
namespace nall {
|
||||
|
||||
static int eval_integer(const char *&s) {
|
||||
if(!*s) throw "unrecognized_integer";
|
||||
int value = 0, x = *s, y = *(s + 1);
|
||||
|
||||
//hexadecimal
|
||||
if(x == '0' && (y == 'X' || y == 'x')) {
|
||||
s += 2;
|
||||
while(true) {
|
||||
if(*s >= '0' && *s <= '9') { value = value * 16 + (*s++ - '0'); continue; }
|
||||
if(*s >= 'A' && *s <= 'F') { value = value * 16 + (*s++ - 'A' + 10); continue; }
|
||||
if(*s >= 'a' && *s <= 'f') { value = value * 16 + (*s++ - 'a' + 10); continue; }
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
//binary
|
||||
if(x == '0' && (y == 'B' || y == 'b')) {
|
||||
s += 2;
|
||||
while(true) {
|
||||
if(*s == '0' || *s == '1') { value = value * 2 + (*s++ - '0'); continue; }
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
//octal (or decimal '0')
|
||||
if(x == '0') {
|
||||
s += 1;
|
||||
while(true) {
|
||||
if(*s >= '0' && *s <= '7') { value = value * 8 + (*s++ - '0'); continue; }
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
//decimal
|
||||
if(x >= '0' && x <= '9') {
|
||||
while(true) {
|
||||
if(*s >= '0' && *s <= '9') { value = value * 10 + (*s++ - '0'); continue; }
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
//char
|
||||
if(x == '\'' && y != '\'') {
|
||||
s += 1;
|
||||
while(true) {
|
||||
value = value * 256 + *s++;
|
||||
if(*s == '\'') { s += 1; return value; }
|
||||
if(!*s) throw "mismatched_char";
|
||||
}
|
||||
}
|
||||
|
||||
throw "unrecognized_integer";
|
||||
}
|
||||
|
||||
static int eval(const char *&s, int depth = 0) {
|
||||
while(*s == ' ' || *s == '\t') s++; //trim whitespace
|
||||
if(!*s) throw "unrecognized_token";
|
||||
int value = 0, x = *s, y = *(s + 1);
|
||||
|
||||
if(*s == '(') {
|
||||
value = eval(++s, 1);
|
||||
if(*s++ != ')') throw "mismatched_group";
|
||||
}
|
||||
|
||||
else if(x == '!') value = !eval(++s, 13);
|
||||
else if(x == '~') value = ~eval(++s, 13);
|
||||
else if(x == '+') value = +eval(++s, 13);
|
||||
else if(x == '-') value = -eval(++s, 13);
|
||||
|
||||
else if((x >= '0' && x <= '9') || x == '\'') value = eval_integer(s);
|
||||
|
||||
else throw "unrecognized_token";
|
||||
|
||||
while(true) {
|
||||
while(*s == ' ' || *s == '\t') s++; //trim whitespace
|
||||
if(!*s) break;
|
||||
x = *s, y = *(s + 1);
|
||||
|
||||
if(depth >= 13) break;
|
||||
if(x == '*') { value *= eval(++s, 13); continue; }
|
||||
if(x == '/') { value /= eval(++s, 13); continue; }
|
||||
if(x == '%') { value %= eval(++s, 13); continue; }
|
||||
|
||||
if(depth >= 12) break;
|
||||
if(x == '+') { value += eval(++s, 12); continue; }
|
||||
if(x == '-') { value -= eval(++s, 12); continue; }
|
||||
|
||||
if(depth >= 11) break;
|
||||
if(x == '<' && y == '<') { value <<= eval(++++s, 11); continue; }
|
||||
if(x == '>' && y == '>') { value >>= eval(++++s, 11); continue; }
|
||||
|
||||
if(depth >= 10) break;
|
||||
if(x == '<' && y == '=') { value = value <= eval(++++s, 10); continue; }
|
||||
if(x == '>' && y == '=') { value = value >= eval(++++s, 10); continue; }
|
||||
if(x == '<') { value = value < eval(++s, 10); continue; }
|
||||
if(x == '>') { value = value > eval(++s, 10); continue; }
|
||||
|
||||
if(depth >= 9) break;
|
||||
if(x == '=' && y == '=') { value = value == eval(++++s, 9); continue; }
|
||||
if(x == '!' && y == '=') { value = value != eval(++++s, 9); continue; }
|
||||
|
||||
if(depth >= 8) break;
|
||||
if(x == '&' && y != '&') { value = value & eval(++s, 8); continue; }
|
||||
|
||||
if(depth >= 7) break;
|
||||
if(x == '^' && y != '^') { value = value ^ eval(++s, 7); continue; }
|
||||
|
||||
if(depth >= 6) break;
|
||||
if(x == '|' && y != '|') { value = value | eval(++s, 6); continue; }
|
||||
|
||||
if(depth >= 5) break;
|
||||
if(x == '&' && y == '&') { value = eval(++++s, 5) && value; continue; }
|
||||
|
||||
if(depth >= 4) break;
|
||||
if(x == '^' && y == '^') { value = (!eval(++++s, 4) != !value); continue; }
|
||||
|
||||
if(depth >= 3) break;
|
||||
if(x == '|' && y == '|') { value = eval(++++s, 3) || value; continue; }
|
||||
|
||||
if(x == '?') {
|
||||
int lhs = eval(++s, 2);
|
||||
if(*s != ':') throw "mismatched_ternary";
|
||||
int rhs = eval(++s, 2);
|
||||
value = value ? lhs : rhs;
|
||||
continue;
|
||||
}
|
||||
if(depth >= 2) break;
|
||||
|
||||
if(depth > 0 && x == ')') break;
|
||||
|
||||
throw "unrecognized_token";
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
bool strint(const char *s, int &result) {
|
||||
try {
|
||||
result = eval_integer(s);
|
||||
return true;
|
||||
} catch(const char*) {
|
||||
result = 0;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool strmath(const char *s, int &result) {
|
||||
try {
|
||||
result = eval(s);
|
||||
return true;
|
||||
} catch(const char*) {
|
||||
result = 0;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
103
nall/string/replace.hpp
Executable file
103
nall/string/replace.hpp
Executable file
@@ -0,0 +1,103 @@
|
||||
#ifndef NALL_STRING_REPLACE_HPP
|
||||
#define NALL_STRING_REPLACE_HPP
|
||||
|
||||
namespace nall {
|
||||
|
||||
string& string::replace(const char *key, const char *token) {
|
||||
int i, z, ksl = strlen(key), tsl = strlen(token), ssl = length();
|
||||
unsigned int replace_count = 0, size = ssl;
|
||||
char *buffer;
|
||||
|
||||
if(ksl <= ssl) {
|
||||
if(tsl > ksl) { //the new string may be longer than the old string...
|
||||
for(i = 0; i <= ssl - ksl;) { //so let's find out how big of a string we'll need...
|
||||
if(!memcmp(data + i, key, ksl)) {
|
||||
replace_count++;
|
||||
i += ksl;
|
||||
} else i++;
|
||||
}
|
||||
size = ssl + ((tsl - ksl) * replace_count);
|
||||
reserve(size);
|
||||
}
|
||||
|
||||
buffer = new char[size + 1];
|
||||
for(i = z = 0; i < ssl;) {
|
||||
if(i <= ssl - ksl) {
|
||||
if(!memcmp(data + i, key, ksl)) {
|
||||
memcpy(buffer + z, token, tsl);
|
||||
z += tsl;
|
||||
i += ksl;
|
||||
} else buffer[z++] = data[i++];
|
||||
} else buffer[z++] = data[i++];
|
||||
}
|
||||
buffer[z] = 0;
|
||||
|
||||
assign(buffer);
|
||||
delete[] buffer;
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
string& string::qreplace(const char *key, const char *token) {
|
||||
int i, l, z, ksl = strlen(key), tsl = strlen(token), ssl = length();
|
||||
unsigned int replace_count = 0, size = ssl;
|
||||
uint8_t x;
|
||||
char *buffer;
|
||||
|
||||
if(ksl <= ssl) {
|
||||
if(tsl > ksl) {
|
||||
for(i = 0; i <= ssl - ksl;) {
|
||||
x = data[i];
|
||||
if(x == '\"' || x == '\'') {
|
||||
l = i;
|
||||
i++;
|
||||
while(data[i++] != x) {
|
||||
if(i == ssl) {
|
||||
i = l;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(!memcmp(data + i, key, ksl)) {
|
||||
replace_count++;
|
||||
i += ksl;
|
||||
} else i++;
|
||||
}
|
||||
size = ssl + ((tsl - ksl) * replace_count);
|
||||
reserve(size);
|
||||
}
|
||||
|
||||
buffer = new char[size + 1];
|
||||
for(i = z = 0; i < ssl;) {
|
||||
x = data[i];
|
||||
if(x == '\"' || x == '\'') {
|
||||
l = i++;
|
||||
while(data[i] != x && i < ssl)i++;
|
||||
if(i >= ssl)i = l;
|
||||
else {
|
||||
memcpy(buffer + z, data + l, i - l);
|
||||
z += i - l;
|
||||
}
|
||||
}
|
||||
if(i <= ssl - ksl) {
|
||||
if(!memcmp(data + i, key, ksl)) {
|
||||
memcpy(buffer + z, token, tsl);
|
||||
z += tsl;
|
||||
i += ksl;
|
||||
replace_count++;
|
||||
} else buffer[z++] = data[i++];
|
||||
} else buffer[z++] = data[i++];
|
||||
}
|
||||
buffer[z] = 0;
|
||||
|
||||
assign(buffer);
|
||||
delete[] buffer;
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
#endif
|
56
nall/string/split.hpp
Executable file
56
nall/string/split.hpp
Executable file
@@ -0,0 +1,56 @@
|
||||
#ifndef NALL_STRING_SPLIT_HPP
|
||||
#define NALL_STRING_SPLIT_HPP
|
||||
|
||||
namespace nall {
|
||||
|
||||
void lstring::split(const char *key, const char *src, unsigned limit) {
|
||||
reset();
|
||||
|
||||
int ssl = strlen(src), ksl = strlen(key);
|
||||
int lp = 0, split_count = 0;
|
||||
|
||||
for(int i = 0; i <= ssl - ksl;) {
|
||||
if(!memcmp(src + i, key, ksl)) {
|
||||
strlcpy(operator[](split_count++), src + lp, i - lp + 1);
|
||||
i += ksl;
|
||||
lp = i;
|
||||
if(!--limit) break;
|
||||
} else i++;
|
||||
}
|
||||
|
||||
operator[](split_count++) = src + lp;
|
||||
}
|
||||
|
||||
void lstring::qsplit(const char *key, const char *src, unsigned limit) {
|
||||
reset();
|
||||
|
||||
int ssl = strlen(src), ksl = strlen(key);
|
||||
int lp = 0, split_count = 0;
|
||||
|
||||
for(int i = 0; i <= ssl - ksl;) {
|
||||
uint8_t x = src[i];
|
||||
|
||||
if(x == '\"' || x == '\'') {
|
||||
int z = i++; //skip opening quote
|
||||
while(i < ssl && src[i] != x) i++;
|
||||
if(i >= ssl) i = z; //failed match, rewind i
|
||||
else {
|
||||
i++; //skip closing quote
|
||||
continue; //restart in case next char is also a quote
|
||||
}
|
||||
}
|
||||
|
||||
if(!memcmp(src + i, key, ksl)) {
|
||||
strlcpy(operator[](split_count++), src + lp, i - lp + 1);
|
||||
i += ksl;
|
||||
lp = i;
|
||||
if(!--limit) break;
|
||||
} else i++;
|
||||
}
|
||||
|
||||
operator[](split_count++) = src + lp;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
#endif
|
52
nall/string/strl.hpp
Executable file
52
nall/string/strl.hpp
Executable file
@@ -0,0 +1,52 @@
|
||||
#ifndef NALL_STRING_STRL_HPP
|
||||
#define NALL_STRING_STRL_HPP
|
||||
|
||||
namespace nall {
|
||||
|
||||
//strlcpy, strlcat based on OpenBSD implementation by Todd C. Miller
|
||||
|
||||
//return = strlen(src)
|
||||
unsigned strlcpy(char *dest, const char *src, unsigned length) {
|
||||
char *d = dest;
|
||||
const char *s = src;
|
||||
unsigned n = length;
|
||||
|
||||
if(n) {
|
||||
while(--n && (*d++ = *s++)); //copy as many bytes as possible, or until null terminator reached
|
||||
}
|
||||
|
||||
if(!n) {
|
||||
if(length) *d = 0;
|
||||
while(*s++); //traverse rest of s, so that s - src == strlen(src)
|
||||
}
|
||||
|
||||
return (s - src - 1); //return length of copied string, sans null terminator
|
||||
}
|
||||
|
||||
//return = strlen(src) + min(length, strlen(dest))
|
||||
unsigned strlcat(char *dest, const char *src, unsigned length) {
|
||||
char *d = dest;
|
||||
const char *s = src;
|
||||
unsigned n = length;
|
||||
|
||||
while(n-- && *d) d++; //find end of dest
|
||||
unsigned dlength = d - dest;
|
||||
n = length - dlength; //subtract length of dest from maximum string length
|
||||
|
||||
if(!n) return dlength + strlen(s);
|
||||
|
||||
while(*s) {
|
||||
if(n != 1) {
|
||||
*d++ = *s;
|
||||
n--;
|
||||
}
|
||||
s++;
|
||||
}
|
||||
*d = 0;
|
||||
|
||||
return dlength + (s - src); //return length of resulting string, sans null terminator
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
41
nall/string/strpos.hpp
Executable file
41
nall/string/strpos.hpp
Executable file
@@ -0,0 +1,41 @@
|
||||
#ifndef NALL_STRING_STRPOS_HPP
|
||||
#define NALL_STRING_STRPOS_HPP
|
||||
|
||||
//usage example:
|
||||
//if(auto pos = strpos(str, key)) print(pos(), "\n");
|
||||
//prints position of key within str, only if it is found
|
||||
|
||||
namespace nall {
|
||||
|
||||
inline optional<unsigned> strpos(const char *str, const char *key) {
|
||||
unsigned ssl = strlen(str), ksl = strlen(key);
|
||||
if(ksl > ssl) return { false, 0 };
|
||||
|
||||
for(unsigned i = 0; i <= ssl - ksl; i++) {
|
||||
if(!memcmp(str + i, key, ksl)) return { true, i };
|
||||
}
|
||||
|
||||
return { false, 0 };
|
||||
}
|
||||
|
||||
inline optional<unsigned> qstrpos(const char *str, const char *key) {
|
||||
unsigned ssl = strlen(str), ksl = strlen(key);
|
||||
if(ksl > ssl) return { false, 0 };
|
||||
|
||||
for(unsigned i = 0; i <= ssl - ksl;) {
|
||||
uint8_t x = str[i];
|
||||
if(x == '\"' || x == '\'') {
|
||||
uint8_t z = i++;
|
||||
while(str[i] != x && i < ssl) i++;
|
||||
if(i >= ssl) i = z;
|
||||
}
|
||||
if(!memcmp(str + i, key, ksl)) return { true, i };
|
||||
i++;
|
||||
}
|
||||
|
||||
return { false, 0 };
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
61
nall/string/trim.hpp
Executable file
61
nall/string/trim.hpp
Executable file
@@ -0,0 +1,61 @@
|
||||
#ifndef NALL_STRING_TRIM_HPP
|
||||
#define NALL_STRING_TRIM_HPP
|
||||
|
||||
namespace nall {
|
||||
|
||||
char* ltrim(char *str, const char *key) {
|
||||
if(!key || !*key) return str;
|
||||
while(strbegin(str, key)) {
|
||||
char *dest = str, *src = str + strlen(key);
|
||||
while(true) {
|
||||
*dest = *src++;
|
||||
if(!*dest) break;
|
||||
dest++;
|
||||
}
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
char* rtrim(char *str, const char *key) {
|
||||
if(!key || !*key) return str;
|
||||
while(strend(str, key)) str[strlen(str) - strlen(key)] = 0;
|
||||
return str;
|
||||
}
|
||||
|
||||
char* trim(char *str, const char *key) {
|
||||
return ltrim(rtrim(str, key), key);
|
||||
}
|
||||
|
||||
char* ltrim_once(char *str, const char *key) {
|
||||
if(!key || !*key) return str;
|
||||
if(strbegin(str, key)) {
|
||||
char *dest = str, *src = str + strlen(key);
|
||||
while(true) {
|
||||
*dest = *src++;
|
||||
if(!*dest) break;
|
||||
dest++;
|
||||
}
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
char* rtrim_once(char *str, const char *key) {
|
||||
if(!key || !*key) return str;
|
||||
if(strend(str, key)) str[strlen(str) - strlen(key)] = 0;
|
||||
return str;
|
||||
}
|
||||
|
||||
char* trim_once(char *str, const char *key) {
|
||||
return ltrim_once(rtrim_once(str, key), key);
|
||||
}
|
||||
|
||||
string& string::ltrim(const char *key) { nall::ltrim(data, key); return *this; }
|
||||
string& string::rtrim(const char *key) { nall::rtrim(data, key); return *this; }
|
||||
string& string::trim (const char *key) { nall::trim (data, key); return *this; }
|
||||
string& string::ltrim_once(const char *key) { nall::ltrim_once(data, key); return *this; }
|
||||
string& string::rtrim_once(const char *key) { nall::rtrim_once(data, key); return *this; }
|
||||
string& string::trim_once (const char *key) { nall::trim_once (data, key); return *this; }
|
||||
|
||||
}
|
||||
|
||||
#endif
|
157
nall/string/utility.hpp
Executable file
157
nall/string/utility.hpp
Executable file
@@ -0,0 +1,157 @@
|
||||
#ifndef NALL_STRING_UTILITY_HPP
|
||||
#define NALL_STRING_UTILITY_HPP
|
||||
|
||||
namespace nall {
|
||||
|
||||
unsigned strlcpy(string &dest, const char *src, unsigned length) {
|
||||
dest.reserve(length);
|
||||
return strlcpy(dest(), src, length);
|
||||
}
|
||||
|
||||
unsigned strlcat(string &dest, const char *src, unsigned length) {
|
||||
dest.reserve(length);
|
||||
return strlcat(dest(), src, length);
|
||||
}
|
||||
|
||||
string substr(const char *src, unsigned start, unsigned length) {
|
||||
string dest;
|
||||
if(length == 0) {
|
||||
//copy entire string
|
||||
dest = src + start;
|
||||
} else {
|
||||
//copy partial string
|
||||
strlcpy(dest, src + start, length + 1);
|
||||
}
|
||||
return dest;
|
||||
}
|
||||
|
||||
/* arithmetic <> string */
|
||||
|
||||
template<unsigned length, char padding> string strhex(uintmax_t value) {
|
||||
string output;
|
||||
unsigned offset = 0;
|
||||
|
||||
//render string backwards, as we do not know its length yet
|
||||
do {
|
||||
unsigned n = value & 15;
|
||||
output[offset++] = n < 10 ? '0' + n : 'a' + n - 10;
|
||||
value >>= 4;
|
||||
} while(value);
|
||||
|
||||
while(offset < length) output[offset++] = padding;
|
||||
output[offset--] = 0;
|
||||
|
||||
//reverse the string in-place
|
||||
for(unsigned i = 0; i < (offset + 1) >> 1; i++) {
|
||||
char temp = output[i];
|
||||
output[i] = output[offset - i];
|
||||
output[offset - i] = temp;
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
template<unsigned length, char padding> string strsigned(intmax_t value) {
|
||||
string output;
|
||||
unsigned offset = 0;
|
||||
|
||||
bool negative = value < 0;
|
||||
if(negative) value = abs(value);
|
||||
|
||||
do {
|
||||
unsigned n = value % 10;
|
||||
output[offset++] = '0' + n;
|
||||
value /= 10;
|
||||
} while(value);
|
||||
|
||||
while(offset < length) output[offset++] = padding;
|
||||
if(negative) output[offset++] = '-';
|
||||
output[offset--] = 0;
|
||||
|
||||
for(unsigned i = 0; i < (offset + 1) >> 1; i++) {
|
||||
char temp = output[i];
|
||||
output[i] = output[offset - i];
|
||||
output[offset - i] = temp;
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
template<unsigned length, char padding> string strunsigned(uintmax_t value) {
|
||||
string output;
|
||||
unsigned offset = 0;
|
||||
|
||||
do {
|
||||
unsigned n = value % 10;
|
||||
output[offset++] = '0' + n;
|
||||
value /= 10;
|
||||
} while(value);
|
||||
|
||||
while(offset < length) output[offset++] = padding;
|
||||
output[offset--] = 0;
|
||||
|
||||
for(unsigned i = 0; i < (offset + 1) >> 1; i++) {
|
||||
char temp = output[i];
|
||||
output[i] = output[offset - i];
|
||||
output[offset - i] = temp;
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
template<unsigned length, char padding> string strbin(uintmax_t value) {
|
||||
string output;
|
||||
unsigned offset = 0;
|
||||
|
||||
do {
|
||||
unsigned n = value & 1;
|
||||
output[offset++] = '0' + n;
|
||||
value >>= 1;
|
||||
} while(value);
|
||||
|
||||
while(offset < length) output[offset++] = padding;
|
||||
output[offset--] = 0;
|
||||
|
||||
for(unsigned i = 0; i < (offset + 1) >> 1; i++) {
|
||||
char temp = output[i];
|
||||
output[i] = output[offset - i];
|
||||
output[offset - i] = temp;
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
//using sprintf is certainly not the most ideal method to convert
|
||||
//a double to a string ... but attempting to parse a double by
|
||||
//hand, digit-by-digit, results in subtle rounding errors.
|
||||
unsigned strdouble(char *str, double value) {
|
||||
char buffer[256];
|
||||
sprintf(buffer, "%f", value);
|
||||
|
||||
//remove excess 0's in fraction (2.500000 -> 2.5)
|
||||
for(char *p = buffer; *p; p++) {
|
||||
if(*p == '.') {
|
||||
char *p = buffer + strlen(buffer) - 1;
|
||||
while(*p == '0') {
|
||||
if(*(p - 1) != '.') *p = 0; //... but not for eg 1.0 -> 1.
|
||||
p--;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
unsigned length = strlen(buffer);
|
||||
if(str) strcpy(str, buffer);
|
||||
return length + 1;
|
||||
}
|
||||
|
||||
string strdouble(double value) {
|
||||
string temp;
|
||||
temp.reserve(strdouble(0, value));
|
||||
strdouble(temp(), value);
|
||||
return temp;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
12
nall/string/variadic.hpp
Executable file
12
nall/string/variadic.hpp
Executable file
@@ -0,0 +1,12 @@
|
||||
#ifndef NALL_STRING_VARIADIC_HPP
|
||||
#define NALL_STRING_VARIADIC_HPP
|
||||
|
||||
namespace nall {
|
||||
|
||||
template<typename... Args> inline void print(Args... args) {
|
||||
printf("%s", (const char*)string(args...));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
265
nall/string/xml.hpp
Executable file
265
nall/string/xml.hpp
Executable file
@@ -0,0 +1,265 @@
|
||||
#ifndef NALL_STRING_XML_HPP
|
||||
#define NALL_STRING_XML_HPP
|
||||
|
||||
//XML subset parser
|
||||
//version 0.05
|
||||
|
||||
namespace nall {
|
||||
|
||||
struct xml_attribute {
|
||||
string name;
|
||||
string content;
|
||||
virtual string parse() const;
|
||||
};
|
||||
|
||||
struct xml_element : xml_attribute {
|
||||
string parse() const;
|
||||
linear_vector<xml_attribute> attribute;
|
||||
linear_vector<xml_element> element;
|
||||
|
||||
protected:
|
||||
void parse_doctype(const char *&data);
|
||||
bool parse_head(string data);
|
||||
bool parse_body(const char *&data);
|
||||
friend xml_element xml_parse(const char *data);
|
||||
};
|
||||
|
||||
inline string xml_attribute::parse() const {
|
||||
string data;
|
||||
unsigned offset = 0;
|
||||
|
||||
const char *source = content;
|
||||
while(*source) {
|
||||
if(*source == '&') {
|
||||
if(strbegin(source, "<")) { data[offset++] = '<'; source += 4; continue; }
|
||||
if(strbegin(source, ">")) { data[offset++] = '>'; source += 4; continue; }
|
||||
if(strbegin(source, "&")) { data[offset++] = '&'; source += 5; continue; }
|
||||
if(strbegin(source, "'")) { data[offset++] = '\''; source += 6; continue; }
|
||||
if(strbegin(source, """)) { data[offset++] = '"'; source += 6; continue; }
|
||||
}
|
||||
|
||||
//reject illegal characters
|
||||
if(*source == '&') return "";
|
||||
if(*source == '<') return "";
|
||||
if(*source == '>') return "";
|
||||
|
||||
data[offset++] = *source++;
|
||||
}
|
||||
|
||||
data[offset] = 0;
|
||||
return data;
|
||||
}
|
||||
|
||||
inline string xml_element::parse() const {
|
||||
string data;
|
||||
unsigned offset = 0;
|
||||
|
||||
const char *source = content;
|
||||
while(*source) {
|
||||
if(*source == '&') {
|
||||
if(strbegin(source, "<")) { data[offset++] = '<'; source += 4; continue; }
|
||||
if(strbegin(source, ">")) { data[offset++] = '>'; source += 4; continue; }
|
||||
if(strbegin(source, "&")) { data[offset++] = '&'; source += 5; continue; }
|
||||
if(strbegin(source, "'")) { data[offset++] = '\''; source += 6; continue; }
|
||||
if(strbegin(source, """)) { data[offset++] = '"'; source += 6; continue; }
|
||||
}
|
||||
|
||||
if(strbegin(source, "<!--")) {
|
||||
if(auto pos = strpos(source, "-->")) {
|
||||
source += pos() + 3;
|
||||
continue;
|
||||
} else {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
if(strbegin(source, "<![CDATA[")) {
|
||||
if(auto pos = strpos(source, "]]>")) {
|
||||
string cdata = substr(source, 9, pos() - 9);
|
||||
data << cdata;
|
||||
offset += strlen(cdata);
|
||||
|
||||
source += offset + 3;
|
||||
continue;
|
||||
} else {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
//reject illegal characters
|
||||
if(*source == '&') return "";
|
||||
if(*source == '<') return "";
|
||||
if(*source == '>') return "";
|
||||
|
||||
data[offset++] = *source++;
|
||||
}
|
||||
|
||||
data[offset] = 0;
|
||||
return data;
|
||||
}
|
||||
|
||||
inline void xml_element::parse_doctype(const char *&data) {
|
||||
name = "!DOCTYPE";
|
||||
const char *content_begin = data;
|
||||
|
||||
signed counter = 0;
|
||||
while(*data) {
|
||||
char value = *data++;
|
||||
if(value == '<') counter++;
|
||||
if(value == '>') counter--;
|
||||
if(counter < 0) {
|
||||
content = substr(content_begin, 0, data - content_begin - 1);
|
||||
return;
|
||||
}
|
||||
}
|
||||
throw "...";
|
||||
}
|
||||
|
||||
inline bool xml_element::parse_head(string data) {
|
||||
data.qreplace("\t", " ");
|
||||
data.qreplace("\r", " ");
|
||||
data.qreplace("\n", " ");
|
||||
while(qstrpos(data, " ")) data.qreplace(" ", " ");
|
||||
data.qreplace(" =", "=");
|
||||
data.qreplace("= ", "=");
|
||||
data.rtrim();
|
||||
|
||||
lstring part;
|
||||
part.qsplit(" ", data);
|
||||
|
||||
name = part[0];
|
||||
if(name == "") throw "...";
|
||||
|
||||
for(unsigned i = 1; i < part.size(); i++) {
|
||||
lstring side;
|
||||
side.qsplit("=", part[i]);
|
||||
if(side.size() != 2) throw "...";
|
||||
|
||||
xml_attribute attr;
|
||||
attr.name = side[0];
|
||||
attr.content = side[1];
|
||||
if(strbegin(attr.content, "\"") && strend(attr.content, "\"")) attr.content.trim_once("\"");
|
||||
else if(strbegin(attr.content, "'") && strend(attr.content, "'")) attr.content.trim_once("'");
|
||||
else throw "...";
|
||||
attribute.append(attr);
|
||||
}
|
||||
}
|
||||
|
||||
inline bool xml_element::parse_body(const char *&data) {
|
||||
while(true) {
|
||||
if(!*data) return false;
|
||||
if(*data++ != '<') continue;
|
||||
if(*data == '/') return false;
|
||||
|
||||
if(strbegin(data, "!DOCTYPE") == true) {
|
||||
parse_doctype(data);
|
||||
return true;
|
||||
}
|
||||
|
||||
if(strbegin(data, "!--")) {
|
||||
if(auto offset = strpos(data, "-->")) {
|
||||
data += offset() + 3;
|
||||
continue;
|
||||
} else {
|
||||
throw "...";
|
||||
}
|
||||
}
|
||||
|
||||
if(strbegin(data, "![CDATA[")) {
|
||||
if(auto offset = strpos(data, "]]>")) {
|
||||
data += offset() + 3;
|
||||
continue;
|
||||
} else {
|
||||
throw "...";
|
||||
}
|
||||
}
|
||||
|
||||
auto offset = strpos(data, ">");
|
||||
if(!offset) throw "...";
|
||||
|
||||
string tag = substr(data, 0, offset());
|
||||
data += offset() + 1;
|
||||
const char *content_begin = data;
|
||||
|
||||
bool self_terminating = false;
|
||||
|
||||
if(strend(tag, "?") == true) {
|
||||
self_terminating = true;
|
||||
tag.rtrim_once("?");
|
||||
} else if(strend(tag, "/") == true) {
|
||||
self_terminating = true;
|
||||
tag.rtrim_once("/");
|
||||
}
|
||||
|
||||
parse_head(tag);
|
||||
if(self_terminating) return true;
|
||||
|
||||
while(*data) {
|
||||
unsigned index = element.size();
|
||||
xml_element node;
|
||||
if(node.parse_body(data) == false) {
|
||||
if(*data == '/') {
|
||||
signed length = data - content_begin - 1;
|
||||
if(length > 0) content = substr(content_begin, 0, length);
|
||||
|
||||
data++;
|
||||
auto offset = strpos(data, ">");
|
||||
if(!offset) throw "...";
|
||||
|
||||
tag = substr(data, 0, offset());
|
||||
data += offset() + 1;
|
||||
|
||||
tag.replace("\t", " ");
|
||||
tag.replace("\r", " ");
|
||||
tag.replace("\n", " ");
|
||||
while(strpos(tag, " ")) tag.replace(" ", " ");
|
||||
tag.rtrim();
|
||||
|
||||
if(name != tag) throw "...";
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
element.append(node);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//ensure there is only one root element
|
||||
inline bool xml_validate(xml_element &document) {
|
||||
unsigned root_counter = 0;
|
||||
|
||||
for(unsigned i = 0; i < document.element.size(); i++) {
|
||||
string &name = document.element[i].name;
|
||||
if(strbegin(name, "?")) continue;
|
||||
if(strbegin(name, "!")) continue;
|
||||
if(++root_counter > 1) return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
inline xml_element xml_parse(const char *data) {
|
||||
xml_element self;
|
||||
|
||||
try {
|
||||
while(*data) {
|
||||
xml_element node;
|
||||
if(node.parse_body(data) == false) {
|
||||
break;
|
||||
} else {
|
||||
self.element.append(node);
|
||||
}
|
||||
}
|
||||
|
||||
if(xml_validate(self) == false) throw "...";
|
||||
return self;
|
||||
} catch(const char*) {
|
||||
xml_element empty;
|
||||
return empty;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
Reference in New Issue
Block a user