From f43d32d6d2cc7ecd04f4f06f20d5a6fc2c87c9ae Mon Sep 17 00:00:00 2001 From: Aki Date: Tue, 12 Mar 2024 01:08:39 +0100 Subject: Another reorganization change that diverts me from crying unable to get rid off singleton madness --- FoundationEx/src/Reader.cpp | 119 ++++++++ FoundationEx/src/Text.cpp | 686 ++++++++++++++++++++++++++++++++++++++++++++ FoundationEx/src/Utils.cpp | 38 +++ 3 files changed, 843 insertions(+) create mode 100644 FoundationEx/src/Reader.cpp create mode 100644 FoundationEx/src/Text.cpp create mode 100644 FoundationEx/src/Utils.cpp (limited to 'FoundationEx/src') diff --git a/FoundationEx/src/Reader.cpp b/FoundationEx/src/Reader.cpp new file mode 100644 index 0000000..0ca49aa --- /dev/null +++ b/FoundationEx/src/Reader.cpp @@ -0,0 +1,119 @@ +/* Starshatter: The Open Source Project + Copyright (c) 2021-2022, Starshatter: The Open Source Project Contributors + Copyright (c) 2011-2012, Starshatter OpenSource Distribution Contributors + Copyright (c) 1997-2006, Destroyer Studios LLC. + + AUTHOR: John DiCamillo + + + OVERVIEW + ======== + Implementation of the Reader class +*/ + +#include + +#include +#include +#include + +#include + + +Text +ConsoleReader::more() +{ + // loop until the user types something + do { + printPrimaryPrompt(); + fillInputBuffer(); + } while (! *p); + + return Text(p); +} + + +void +ConsoleReader::printPrimaryPrompt() +{ + std::printf("- "); +} + + +void +ConsoleReader::fillInputBuffer() +{ + std::fgets(buffer, 980, stdin); + p = buffer; + while (std::isspace(*p)) p++; +} + + +FileReader::FileReader(const char* fname) : + filename(fname), + done(0) +{ +} + + +Text +FileReader::more() +{ + if (done) return Text(); + + std::fstream fin(filename, std::fstream::in); + + if (!fin) { + Print("ERROR(Parse): Could not open file '%s'\n", filename.data()); + return Text(); + } + + Text result; + char buf[1000], newline; + + while (fin.get(buf, 1000)) { + result.append(buf); + fin.get(newline); + result.append(newline); + } + + done = 1; + return result; +} + + +BlockReader::BlockReader(const char* block) : + data((char*) block), + done(0), + length(0) +{ +} + + +BlockReader::BlockReader(const char* block, int len) : + data((char*) block), + done(0), + length(len) +{ +} + + +Text +BlockReader::more() +{ + if (done) return Text(); + + if (length) { + Text result(data, length); + done = 1; + return result; + } + else if (data) { + Text result(data); + done = 1; + return result; + } + + done = 1; + return Text(); +} diff --git a/FoundationEx/src/Text.cpp b/FoundationEx/src/Text.cpp new file mode 100644 index 0000000..1f46c2e --- /dev/null +++ b/FoundationEx/src/Text.cpp @@ -0,0 +1,686 @@ +/* Starshatter: The Open Source Project + Copyright (c) 2021-2022, Starshatter: The Open Source Project Contributors + Copyright (c) 2011-2012, Starshatter OpenSource Distribution Contributors + Copyright (c) 1997-2006, Destroyer Studios LLC. + + AUTHOR: John DiCamillo + + + OVERVIEW + ======== + Implementation of the Text class +*/ + +#include + +#include +#include +#include + +// +-------------------------------------------------------------------+ +// SPECIAL TEXT REP FOR NULL STRINGS +// This is used only by the default constructor for the Text object, +// to prevent extra rep allocation when constructing empty strings. + +TextRep TextRep::nullrep; + +TextRep::TextRep() + : ref(1234567), data(0), length(0), hash(0), sensitive(true) +{ + data = new char[4]; + + if (data) + std::memset(data, 0, 4); +} + +// +-------------------------------------------------------------------+ + + +TextRep::TextRep(const char* s) + : ref(1), length(0), sensitive(true) +{ + if (s) length = std::strlen(s); + + data = new char[length+1]; + + if (data) { + if (s) std::strcpy(data, s); + else data[length] = '\0'; + + dohash(); + } +} + +TextRep::TextRep(const char* s, int len) + : ref(1), length(len), sensitive(true) +{ + if (length < 0) length = 0; + + data = new char[length+1]; + + if (data) { + std::memcpy(data, s, length); + data[length] = '\0'; + dohash(); + } +} + +TextRep::TextRep(char c, int len) + : ref(1), length(len), sensitive(true) +{ + if (length < 0) length = 0; + + data = new char[length+1]; + + if (data) { + std::memset(data, c, length); + data[length] = '\0'; + dohash(); + } +} + +TextRep::TextRep(const TextRep* rep) + : ref(1) +{ + length = rep->length; + + data = new char[length+1]; + + hash = rep->hash; + sensitive = rep->sensitive; + + if (data) + std::strcpy(data, rep->data); +} + +TextRep::~TextRep() +{ + delete[] data; +} + +void +TextRep::addref() +{ + ref++; +} + +long +TextRep::deref() +{ + long r = --ref; + return r; +} + +inline static void mash(unsigned& hash, unsigned chars) +{ + hash = (chars ^ ((hash << 5) | (hash >> (8*sizeof(unsigned) - 5)))); +} + +void +TextRep::dohash() +{ + unsigned hv = (unsigned)length; // Mix in the string length. + unsigned i = length*sizeof(char)/sizeof(unsigned); + const unsigned* p = (const unsigned*)data; + + while (i--) + mash(hv, *p++); // XOR in the characters. + + // XOR in any remaining characters: + i = length*sizeof(char)%sizeof(unsigned); + if (i) { + unsigned h = 0; + const char* c = (const char*)p; + while (i--) + h = ((h << 8*sizeof(char)) | *c++); + mash(hv, h); + } + + hash = hv; +} + +// +-------------------------------------------------------------------+ + +Text::Text() +{ + rep = &TextRep::nullrep; + rep->addref(); + sym = rep->data; +} + +Text::Text(char c) +{ + char buf[2]; buf[0] = c; buf[1] = '\0'; + + rep = new TextRep(buf); + + if (!rep) { + rep = &TextRep::nullrep; + rep->addref(); + } + + sym = rep->data; +} + +Text::Text(const char* s) +{ + rep = new TextRep(s); + + if (!rep) { + rep = &TextRep::nullrep; + rep->addref(); + } + + sym = rep->data; +} + +Text::Text(const char* s, int len) +{ + rep = new TextRep(s, len); + + if (!rep) { + rep = &TextRep::nullrep; + rep->addref(); + } + + sym = rep->data; +} + +Text::Text(char c, int len) +{ + rep = new TextRep(c, len); + + if (!rep) { + rep = &TextRep::nullrep; + rep->addref(); + } + + sym = rep->data; +} + +Text::Text(const Text& s) +{ + rep = s.rep; + rep->addref(); + sym = rep->data; +} + +Text::~Text() +{ + if (rep->deref() == 0) delete rep; + + rep = &TextRep::nullrep; + sym = rep->data; +} + +Text& +Text::operator=(const char* s) +{ + if (rep->deref() == 0) delete rep; + rep = new TextRep(s); + + if (!rep) + rep = &TextRep::nullrep; + sym = rep->data; + return *this; +} + +Text& +Text::operator=(const Text& s) +{ + s.rep->addref(); + if (rep->deref() == 0) delete rep; + rep = s.rep; + sym = rep->data; + return *this; +} + +Text +Text::operator+(char c) +{ + char* buf = new char[rep->length + 2]; + + if (buf) { + std::strcpy(buf, sym); + buf[rep->length] = c; + buf[rep->length+1] = '\0'; + Text retval(buf); + delete [] buf; + return retval; + } + + else { + return *this; + } +} + +Text +Text::operator+(const char* s) +{ + char* buf = new char[std::strlen(s) + rep->length + 1]; + + if (buf) { + std::strcpy(buf, sym); + std::strcat(buf, s); + Text retval(buf); + delete [] buf; + return retval; + } + + else { + return *this; + } +} + +Text +Text::operator+(const Text& s) +{ + char* buf = new char[s.rep->length + rep->length + 1]; + + if (buf) { + std::strcpy(buf, sym); + std::strcat(buf, s.sym); + Text retval(buf); + delete [] buf; + return retval; + } + + else { + return *this; + } +} + +bool +Text::isSensitive() const +{ + return rep->sensitive; +} + +void +Text::setSensitive(bool s) +{ + rep->sensitive = s; +} + +Text& +Text::append(char c) +{ + char* buf = new char[rep->length + 2]; + + if (buf) { + std::strcpy(buf, sym); + buf[rep->length] = c; + buf[rep->length+1] = '\0'; + if (rep->deref() == 0) delete rep; + + rep = new TextRep(buf); + + if (!rep) + rep = &TextRep::nullrep; + + sym = rep->data; + delete [] buf; + } + + return *this; +} + +Text& +Text::append(const char* s) +{ + char* buf = new char[std::strlen(s) + rep->length + 1]; + + if (buf) { + std::strcpy(buf, sym); + std::strcat(buf, s); + if (rep->deref() == 0) delete rep; + + rep = new TextRep(buf); + + if (!rep) + rep = &TextRep::nullrep; + + sym = rep->data; + delete [] buf; + } + + return *this; +} + +Text& +Text::append(const Text& s) +{ + char* buf = new char[s.rep->length + rep->length + 1]; + + if (buf) { + int lenA = rep->length; + int lenB = s.rep->length; + + std::memcpy(buf, sym, lenA); + std::memcpy(buf + lenA, s.sym, lenB); + buf[lenA + lenB] = 0; + + if (rep->deref() == 0) delete rep; + + rep = new TextRep(buf); + + if (!rep) + rep = &TextRep::nullrep; + + sym = rep->data; + delete [] buf; + } + + return *this; +} + +void +Text::clone() +{ + if (rep->ref > 1) { + rep->deref(); + + TextRep* t = new TextRep(rep); + + rep = t; + + if (!rep) + rep = &TextRep::nullrep; + + sym = rep->data; + } +} + +char +Text::operator[](int index) const +{ + if (index < (int) rep->length) + return sym[index]; + else + throw "BOUNDS ERROR"; + + return '\0'; +} + +char +Text::operator()(int index) const +{ + return sym[index]; +} + +char& +Text::operator[](int index) +{ + if (index < (int) rep->length) { + clone(); + return (char&) sym[index]; + } + else + throw "BOUNDS ERROR"; + + return (char&) sym[0]; +} + +char& +Text::operator()(int index) +{ + clone(); + return (char&) sym[index]; +} + +Text +Text::operator()(int start, int len) const +{ + if (start > rep->length || len <= 0) + return Text(); + + if (start + len > rep->length) + len = rep->length - start; + + char* buf = new char[len+1]; + + if (buf) { + std::strncpy(buf, sym+start, len); + buf[len] = '\0'; + + Text retval(buf); + delete [] buf; + return retval; + } + + return Text(); +} + + +bool +Text::empty() const +{ + return !rep || rep->length < 1; +} + + +bool +Text::contains(char c) const +{ + if (rep->length > 0) { + if (!rep->sensitive) { + char alt = c; + if (std::islower(alt)) alt = std::toupper(alt); + else if (std::isupper(alt)) alt = std::tolower(alt); + + if (std::strchr(rep->data, alt) != 0) + return true; + } + + if (std::strchr(rep->data, c) != 0) + return true; + } + + return false; +} + +bool +Text::contains(const char* pattern) const +{ + if (rep->length > 0 && pattern && *pattern) { + if (rep->sensitive) { + if (std::strstr(rep->data, pattern) != 0) + return true; + } + else { + Text smash1(*this); + smash1.toLower(); + Text smash2(pattern); + smash2.toLower(); + + if (std::strstr(smash1.data(), smash2.data()) != 0) + return true; + } + } + + return false; +} + +bool +Text::containsAnyOf(const char* charSet) const +{ + if (rep->length > 0 && charSet && *charSet) { + if (rep->sensitive) { + if (strpbrk(rep->data, charSet) != 0) + return true; + } + else { + Text smash1(*this); + smash1.toLower(); + Text smash2(charSet); + smash2.toLower(); + + if (strpbrk(smash1.data(), smash2.data()) != 0) + return true; + } + } + + return false; +} + +int +Text::indexOf(char c) const +{ + if (rep->length > 0) { + if (!rep->sensitive) { + char alt = c; + if (std::islower(alt)) alt = std::toupper(alt); + else if (std::isupper(alt)) alt = std::tolower(alt); + + const char* p = std::strchr(rep->data, alt); + + if (p) + return (p - rep->data); + } + + const char* p = std::strchr(rep->data, c); + + if (p) + return (p - rep->data); + } + + return -1; +} + +int +Text::indexOf(const char* pattern) const +{ + if (rep->length > 0 && pattern && *pattern) { + if (rep->sensitive) { + const char* p = std::strstr(rep->data, pattern); + if (p) return (p - rep->data); + } + else { + Text smash1(*this); + smash1.toLower(); + Text smash2(pattern); + smash2.toLower(); + + const char* p = std::strstr(smash1.data(), smash2.data()); + if (p) return (p - smash1.data()); + } + } + + return -1; +} + +void +Text::toLower() +{ + clone(); + size_t n = rep->length; + char* p = (char*) sym; + while (n--) { + *p = std::tolower((unsigned char)*p); + p++; + } + + rep->dohash(); +} + +void +Text::toUpper() +{ + clone(); + size_t n = rep->length; + char* p = (char*) sym; + while ( n-- ) { + *p = std::toupper((unsigned char)*p); + p++; + } + + rep->dohash(); +} + +Text +Text::substring(int start, int length) +{ + Text result; + + if (start >= 0 && start < (int) rep->length && length > 0) { + if (start + length > (int) rep->length) + length = (int) rep->length - start; + + const char* s = sym + start; + + result.rep = new TextRep(s, length); + + if (!result.rep) + result.rep = &TextRep::nullrep; + + result.sym = result.rep->data; + } + + return result; +} + +Text +Text::trim() +{ + Text result; + + if (rep->length) { + const char* p = sym; + const char* q = sym + rep->length-1; + + while (p && *p && isspace(*p)) p++; + while (q>p && *q && isspace(*q)) q--; + + result = substring(p-sym, q-p+1); + } + + return result; +} + +Text +Text::replace(const char* pattern, const char* substitution) +{ + Text result; + + if (rep->length && pattern && *pattern) { + const char* pos = rep->data; + const char* bound = rep->data + rep->length; + int skip = std::strlen(pattern); + do { + const char* p = std::strstr(pos, pattern); + if (p) { + int len = p - pos; + result.append(Text(pos, len)); + result.append(substitution); + pos = p + skip; + } + else if (pos < bound) { + result.append(pos); + break; + } + } + while (pos < bound); + } + + return result; +} + +Text +Text::concat(const char* tail) const +{ + Text result(*this); + result.append(tail); + return result; +} + +Text +Text::format(const char* fmt, ...) +{ + char buf[2048]; + std::va_list args; + va_start(args, fmt); + int len = std::vsnprintf(buf, 2048, fmt, args); + Text result(buf, len); + va_end(args); + return result; +} diff --git a/FoundationEx/src/Utils.cpp b/FoundationEx/src/Utils.cpp new file mode 100644 index 0000000..827ecba --- /dev/null +++ b/FoundationEx/src/Utils.cpp @@ -0,0 +1,38 @@ +/* Starshatter: The Open Source Project + Copyright (c) 2021-2022, Starshatter: The Open Source Project Contributors + Copyright (c) 2011-2012, Starshatter OpenSource Distribution Contributors + Copyright (c) 1997-2006, Destroyer Studios LLC. +*/ + +#include + +#include +#include + + +FILE* ErrLog = nullptr; + + +void AssignErrLog(FILE * out) +{ + ErrLog = out; +} + + +int CloseErrLog() +{ + if (ErrLog) + return fclose(ErrLog); + return 0; +} + + +void Print(const char* fmt, ...) +{ + if (!ErrLog) return; + va_list args; + va_start(args, fmt); + vfprintf(ErrLog, fmt, args); + fflush(ErrLog); + va_end(args); +} -- cgit v1.1