Skip to content

Commit

Permalink
Merge pull request #292 from parasol-framework/test/patterns
Browse files Browse the repository at this point in the history
Improved SVG pattern support
  • Loading branch information
paul-manias authored Dec 22, 2024
2 parents fdebda1 + d9b923b commit 27f88e3
Show file tree
Hide file tree
Showing 26 changed files with 510 additions and 213 deletions.
11 changes: 8 additions & 3 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -363,10 +363,15 @@ endif ()
if (MSVC)
# Turn off ugly warnings
add_compile_definitions ("_CRT_SECURE_NO_WARNINGS")
set (CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreadedDLL")
# These options override sub-projects linking to incorrect standard libraries.
# Use NODEFAULTLIB to override sub-projects linking to incorrect standard libraries.
# https://learn.microsoft.com/en-us/previous-versions/visualstudio/visual-studio-6.0/aa267384(v=vs.60)?redirectedfrom=MSDN
add_link_options ("/NODEFAULTLIB:libcmt.lib" "/NODEFAULTLIB:libcmtd.lib" "/NODEFAULTLIB:msvcrtd.lib")
if (PARASOL_VLOG)
set (CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreadedDebugDLL")
add_link_options ("/NODEFAULTLIB:libc.lib" "/NODEFAULTLIB:libcmt.lib" "/NODEFAULTLIB:libc.lib" "/NODEFAULTLIB:libcmtd.lib" "/NODEFAULTLIB:msvcrt.lib")
else ()
set (CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreadedDLL")
add_link_options ("/NODEFAULTLIB:libcmt.lib" "/NODEFAULTLIB:libcmtd.lib" "/NODEFAULTLIB:msvcrtd.lib")
endif ()
# add_link_options ("/VERBOSE:LIB")
if (ENABLE_ANALYSIS)
# Note that this option is not compatible with /ZI (edit-and-continue). To rectify complaints about the asan DLL, you may also need a line like this one added to each entry in launch.vs.json:
Expand Down
10 changes: 7 additions & 3 deletions include/parasol/modules/core.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,10 @@
#include <array>
#endif

#if defined(_DEBUG) && defined(__linux__)
#include <signal.h>
#if defined(_DEBUG)
#ifndef _MSC_VER
#include <signal.h>
#endif
#endif

#ifndef DEFINE_ENUM_FLAG_OPERATORS
Expand Down Expand Up @@ -1519,8 +1521,10 @@ template <class T> T roundup(T Num, LONG Alignment) {
#ifdef _DEBUG
#ifdef _MSC_VER
#define DEBUG_BREAK __debugbreak();
#else
#elif __linux__
#define DEBUG_BREAK raise(SIGTRAP);
#else
#define DEBUG_BREAK
#endif
#else
#define DEBUG_BREAK
Expand Down
68 changes: 30 additions & 38 deletions include/parasol/strings.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ void split(InType Input, OutIt Output, char Sep = ',') noexcept
auto end = Input.end();
auto current = begin;
while (begin != end) {
if (*begin == Sep) {
if (*begin IS Sep) {
*Output++ = std::string(current, begin);
current = ++begin;
}
Expand All @@ -29,45 +29,40 @@ void split(InType Input, OutIt Output, char Sep = ',') noexcept
inline void ltrim(std::string &String, const std::string &Whitespace = " \n\r\t") noexcept
{
const auto start = String.find_first_not_of(Whitespace);
if ((start != std::string::npos) and (start != 0)) String.erase(0, start);
if (start != std::string::npos) String.erase(0, start);
}

inline void rtrim(std::string &String, const std::string &Whitespace = " \n\r\t") noexcept
{
const auto end = String.find_last_not_of(Whitespace);
if ((end != std::string::npos) and (end != String.size()-1)) String.erase(end+1, String.size()-end);
if (end != std::string::npos) String.erase(end + 1);
}

inline void trim(std::string &String, const std::string &Whitespace = " \n\r\t") noexcept
{
const auto start = String.find_first_not_of(Whitespace);
if ((start != std::string::npos) and (start != 0)) String.erase(0, start);

const auto end = String.find_last_not_of(Whitespace);
if ((end != std::string::npos) and (end != String.size()-1)) String.erase(end+1, String.size()-end);
ltrim(String, Whitespace);
rtrim(String, Whitespace);
}

inline void camelcase(std::string &s) noexcept {
bool raise = true;
for (std::size_t i=0; i < s.size(); i++) {
for (auto &ch : s) {
if (raise) {
s[i] = std::toupper(s[i]);
ch = std::toupper(ch);
raise = false;
}
else if (s[i] <= 0x20) raise = true;
else if (unsigned(ch) <= 0x20) raise = true;
}
}

// Case-insensitive string comparison, both of which must be the same length.

[[nodiscard]] inline bool iequals(const std::string_view lhs, const std::string_view rhs) noexcept
{
auto ichar_equals = [](char a, char b) {
return std::tolower((unsigned char)(a)) == std::tolower((unsigned char)(b));
};

if (lhs.size() != rhs.size()) return false;
return std::ranges::equal(lhs, rhs, ichar_equals);
return std::equal(lhs.begin(), lhs.end(), rhs.begin(), rhs.end(), [](char a, char b) {
return std::tolower(static_cast<unsigned char>(a)) IS std::tolower(static_cast<unsigned char>(b));
});
}

[[nodiscard]] inline bool wildcmp(const std::string_view Wildcard, std::string_view String, bool Case = false) noexcept
Expand All @@ -80,7 +75,7 @@ inline void camelcase(std::string &s) noexcept {
while ((w < Wildcard.size()) and (s < String.size())) {
bool fail = false;
if (Wildcard[w] IS '*') {
while ((Wildcard[w] IS '*') and (w < Wildcard.size())) w++;
while (w < Wildcard.size() and Wildcard[w] IS '*') w++;
if (w IS Wildcard.size()) return true; // Wildcard terminated with a '*'; rest of String will match.

auto i = Wildcard.find_first_of("*|", w); // Count the printable characters after the '*'
Expand All @@ -99,8 +94,8 @@ inline void camelcase(std::string &s) noexcept {
if (Wildcard[w] IS String[s]) break;
}
else {
auto char1 = Wildcard[w]; if ((char1 >= 'A') and (char1 <= 'Z')) char1 = char1 - 'A' + 'a';
auto char2 = String[s]; if ((char2 >= 'A') and (char2 <= 'Z')) char2 = char2 - 'A' + 'a';
auto char1 = std::tolower(static_cast<unsigned char>(Wildcard[w]));
auto char2 = std::tolower(static_cast<unsigned char>(String[s]));
if (char1 IS char2) break;
}
s++;
Expand All @@ -117,8 +112,8 @@ inline void camelcase(std::string &s) noexcept {
if (Wildcard[w++] != String[s++]) fail = true;
}
else {
auto char1 = Wildcard[w++]; if ((char1 >= 'A') and (char1 <= 'Z')) char1 = char1 - 'A' + 'a';
auto char2 = String[s++]; if ((char2 >= 'A') and (char2 <= 'Z')) char2 = char2 - 'A' + 'a';
auto char1 = std::tolower(static_cast<unsigned char>(Wildcard[w++]));
auto char2 = std::tolower(static_cast<unsigned char>(String[s++]));
if (char1 != char2) fail = true;
}
}
Expand All @@ -131,8 +126,8 @@ inline void camelcase(std::string &s) noexcept {
if (Wildcard[w++] != String[s++]) fail = true;
}
else {
auto char1 = Wildcard[w++]; if ((char1 >= 'A') and (char1 <= 'Z')) char1 = char1 - 'A' + 'a';
auto char2 = String[s++]; if ((char2 >= 'A') and (char2 <= 'Z')) char2 = char2 - 'A' + 'a';
auto char1 = std::tolower(static_cast<unsigned char>(Wildcard[w++]));
auto char2 = std::tolower(static_cast<unsigned char>(String[s++]));
if (char1 != char2) fail = true;
}
}
Expand All @@ -149,8 +144,7 @@ inline void camelcase(std::string &s) noexcept {
}

if (String.size() IS s) {
if (Wildcard.size() IS w) return true;
else if (Wildcard[w] IS '|') return true;
if (w IS Wildcard.size() or Wildcard[w] IS '|') return true;
}

if ((w < Wildcard.size()) and (Wildcard[w] IS '*')) return true;
Expand All @@ -163,11 +157,9 @@ inline void camelcase(std::string &s) noexcept {
[[nodiscard]] inline bool startswith(const std::string_view StringA, const std::string_view StringB) noexcept
{
if (StringA.size() > StringB.size()) return false;
std::size_t i;
for (i = 0; i < StringA.size(); i++) {
if (std::tolower(StringA[i]) != std::tolower(StringB[i])) return false;
}
return true;
return std::equal(StringA.begin(), StringA.end(), StringB.begin(), [](char a, char b) {
return std::tolower(static_cast<unsigned char>(a)) IS std::tolower(static_cast<unsigned char>(b));
});
}

[[nodiscard]] inline bool startswith(const std::string_view StringA, CSTRING StringB) noexcept
Expand Down Expand Up @@ -221,11 +213,11 @@ template <class T> inline LONG strcopy(T &&Source, STRING Dest, LONG Length = 0x

[[nodiscard]] inline LONG strsearch(const std::string_view Keyword, CSTRING String) noexcept
{
LONG i;
LONG pos = 0;
size_t i;
size_t pos = 0;
while (String[pos]) {
for (i=0; Keyword[i]; i++) if (String[pos+i] != Keyword[i]) break;
if (!Keyword[i]) return pos;
for (i=0; i < Keyword.size(); i++) if (String[pos+i] != Keyword[i]) break;
if (i IS Keyword.size()) return pos;
for (++pos; (String[pos] & 0xc0) IS 0x80; pos++);
}

Expand All @@ -236,11 +228,11 @@ template <class T> inline LONG strcopy(T &&Source, STRING Dest, LONG Length = 0x

[[nodiscard]] inline LONG strisearch(const std::string_view Keyword, CSTRING String) noexcept
{
LONG i;
LONG pos = 0;
size_t i;
size_t pos = 0;
while (String[pos]) {
for (i=0; Keyword[i]; i++) if (std::toupper(String[pos+i]) != std::toupper(Keyword[i])) break;
if (!Keyword[i]) return pos;
for (i=0; i < Keyword.size(); i++) if (std::toupper(String[pos+i]) != std::toupper(Keyword[i])) break;
if (i IS Keyword.size()) return pos;
for (++pos; (String[pos] & 0xc0) IS 0x80; pos++);
}

Expand Down
10 changes: 7 additions & 3 deletions src/core/defs/core.fdl
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,10 @@ module({ name="Core", copyright="Paul Manias 1996-2024", timestamp=20241015 }, f
privateNames({ "ScriptArg", "CoreBase", "RootModule" })

priority([[
#if defined(_DEBUG) && defined(__linux__)
#include <signal.h>
#if defined(_DEBUG)
#ifndef _MSC_VER
#include <signal.h>
#endif
#endif

#ifndef DEFINE_ENUM_FLAG_OPERATORS
Expand Down Expand Up @@ -576,8 +578,10 @@ template <class T> T roundup(T Num, LONG Alignment) {
#ifdef _DEBUG
#ifdef _MSC_VER
#define DEBUG_BREAK __debugbreak();
#else
#elif __linux__
#define DEBUG_BREAK raise(SIGTRAP);
#else
#define DEBUG_BREAK
#endif
#else
#define DEBUG_BREAK
Expand Down
6 changes: 3 additions & 3 deletions src/core/fs_resolution.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -113,9 +113,9 @@ ERR ResolvePath(const std::string_view &pPath, RSF Flags, std::string *Result)

bool resolved = false;
#ifdef _WIN32
if ((std::tolower(Path[0]) >= 'a') and (std::tolower(Path[0]) <= 'z') and (Path[1] IS ':')) {
resolved = true; // Windows drive letter reference discovered
if ((Path[2] != '/') and (Path[2] != '\\')) {
if ((Path.size() >= 2) and (std::tolower(Path[0]) >= 'a') and (std::tolower(Path[0]) <= 'z') and (Path[1] IS ':')) {
resolved = true;
if ((Path.size() >= 3) and (Path[2] != '/') and (Path[2] != '\\')) {
// Ensure that the path is correctly formed in order to pass test_path()
src = { Path[0], ':', '\\' };
src.append(Path, 2, std::string::npos);
Expand Down
14 changes: 6 additions & 8 deletions src/core/lib_filesystem.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2402,20 +2402,18 @@ ERR fs_getinfo(std::string_view Path, FileInfo *Info, LONG InfoSize)
}
}

for (len=0; Path[len]; len++);

if ((Path[len-1] IS '/') or (Path[len-1] IS '\\')) Info->Flags |= RDF::FOLDER|RDF::TIME;
if (Path.ends_with('/') or Path.ends_with('\\')) Info->Flags |= RDF::FOLDER|RDF::TIME;
else if (dir) Info->Flags |= RDF::FOLDER|RDF::TIME;
else Info->Flags |= RDF::FILE|RDF::SIZE|RDF::TIME;

// Extract the file name

i = len;
if ((Path[i-1] IS '/') or (Path[i-1] IS '\\')) i--;

while ((i > 0) and (Path[i-1] != '/') and (Path[i-1] != '\\') and (Path[i-1] != ':')) i--;
size_t fi;
if (Path.ends_with('/') or Path.ends_with('\\')) fi = Path.find_last_of("/\\:", Path.size()-2);
else fi = Path.find_last_of("/\\:");

i = strcopy(Path.data() + i, Info->Name, MAX_FILENAME-2);
if (fi IS std::string::npos) i = strcopy(Path.data(), Info->Name, MAX_FILENAME - 2);
else i = strcopy(Path.data() + fi + 1, Info->Name, MAX_FILENAME - 2);

if ((Info->Flags & RDF::FOLDER) != RDF::NIL) {
if (Info->Name[i-1] IS '\\') Info->Name[i-1] = '/';
Expand Down
3 changes: 3 additions & 0 deletions src/core/microsoft/windows.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -409,6 +409,9 @@ extern "C" ERR winInitialise(unsigned int *PathHash, BREAK_HANDLER BreakHandler)
// This is only needed if the application crashes and a stack trace is printed.
SymSetOptions(SymGetOptions() | SYMOPT_LOAD_LINES | SYMOPT_DEFERRED_LOADS);
if (SymInitialize(GetCurrentProcess(), 0, TRUE)) glSymbolsLoaded = TRUE;
// These hooks prevent MSVC dialog boxes from appearing when an assert() is made.
_CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_FILE | _CRTDBG_MODE_DEBUG );
_CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR );
#endif

// This turns off dialog boxes that Microsoft forces upon the user in certain situations (e.g. "No Disk in Drive"
Expand Down
2 changes: 1 addition & 1 deletion src/document/functions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -320,7 +320,7 @@ static ERR insert_text(extDocument *Self, RSTREAM *Stream, stream_char &Index, c
auto ws = Self->NoWhitespace; // Retrieve previous whitespace state
for (unsigned i=0; i < Text.size(); ) {
if (unsigned(Text[i]) <= 0x20) { // Whitespace encountered
for (++i; (unsigned(Text[i]) <= 0x20) and (i < Text.size()); i++);
for (++i; (i < Text.size()) and (unsigned(Text[i]) <= 0x20); i++);
if (!ws) et.text += ' ';
ws = true;
}
Expand Down
2 changes: 1 addition & 1 deletion src/document/tests/test-doc.fluid
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ function testLinks2() crcTest('Links2', 'links.rpl?font=Noto Sans&font-size
function testLists() crcTest('Lists', 'lists.rpl', 0xa466f7e9) end
function testLogic() crcTest('Logic', 'logic.rpl', 0x085f7d00) end
function testParagraphs() crcTest('Paragraphs', 'paragraphs.rpl', 0xa3b93738) end
function testTables() crcTest('Tables', 'tables.rpl', 0x23e9a622) end
function testTables() crcTest('Tables', 'tables.rpl', 0x907030c8) end
function testWidgets() crcTest('Widgets', 'widgets.rpl', 0xe3137ec7) end

-----------------------------------------------------------------------------------------------------------------------
Expand Down
16 changes: 7 additions & 9 deletions src/fluid/fluid.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -630,6 +630,7 @@ ERR load_include(objScript *Script, CSTRING IncName)
static CSTRING load_include_struct(lua_State *Lua, CSTRING Line, CSTRING Source)
{
pf::Log log("load_include");

LONG i;
for (i=0; (Line[i] >= 0x20) and (Line[i] != ':'); i++);

Expand Down Expand Up @@ -661,24 +662,21 @@ static CSTRING load_include_struct(lua_State *Lua, CSTRING Line, CSTRING Source)

static BYTE datatype(std::string_view String)
{
LONG i = 0;
while ((String[i]) and (String[i] <= 0x20)) i++; // Skip white-space
size_t i = 0;
while ((i < String.size()) and (String[i] <= 0x20)) i++; // Skip white-space

if ((String[i] IS '0') and (String[i+1] IS 'x')) {
for (i+=2; String[i]; i++) {
if (((String[i] >= '0') and (String[i] <= '9')) or
((String[i] >= 'A') and (String[i] <= 'F')) or
((String[i] >= 'a') and (String[i] <= 'f')));
else return 's';
for (i+=2; i < String.size(); i++) {
if (!std::isxdigit(String[i])) return 's';
}
return 'h';
}

bool is_number = true;
bool is_float = false;

for (; (String[i]) and (is_number); i++) {
if (((String[i] < '0') or (String[i] > '9')) and (String[i] != '.') and (String[i] != '-')) is_number = false;
for (; (i < String.size()) and (is_number); i++) {
if ((!std::isdigit(String[i])) and (String[i] != '.') and (String[i] != '-')) is_number = false;
if (String[i] IS '.') is_float = true;
}

Expand Down
2 changes: 1 addition & 1 deletion src/network/netsocket/netsocket.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1344,7 +1344,7 @@ void win32_netresponse(OBJECTPTR SocketObject, SOCKET_HANDLE SocketHandle, LONG

#ifdef _DEBUG
static const CSTRING msg[] = { "None", "Write", "Read", "Accept", "Connect", "Close" };
log.traceBranch("[%d:%d:%p], %s, Error %d, InUse: %d, WinRecursion: %d", Socket->UID, SocketHandle, ClientSocket, msg[Message], Error, Socket->InUse, Socket->WinRecursion);
log.traceBranch("[%d:%d:%p], %s, Error %d, InUse: %d, WinRecursion: %d", Socket->UID, SocketHandle, ClientSocket, msg[Message], LONG(Error), Socket->InUse, Socket->WinRecursion);
#endif

pf::SwitchContext context(Socket);
Expand Down
1 change: 0 additions & 1 deletion src/network/win32/winsockwrappers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -496,7 +496,6 @@ const char * StartupWinsock() // Return zero if succesful
glWinsockInitialised = TRUE;
}

csNetLookup.unlock();
return NULL;
}

Expand Down
4 changes: 2 additions & 2 deletions src/svg/anim_parsing.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -176,8 +176,8 @@ static ERR set_anim_property(anim_base &Anim, XMLTag &Tag, ULONG Hash, const std
Anim.values.clear();
LONG s, v = 0;
while (v < std::ssize(Value)) {
while ((Value[v]) and (Value[v] <= 0x20)) v++;
for (s=v; (Value[s]) and (Value[s] != ';'); s++);
while ((v < std::ssize(Value)) and (Value[v] <= 0x20)) v++;
for (s=v; (s < std::ssize(Value)) and (Value[s] != ';'); s++);
Anim.values.push_back(std::string(Value.substr(v, s-v)));
v = s;
if (Value[v] IS ';') v++;
Expand Down
Loading

0 comments on commit 27f88e3

Please sign in to comment.