summaryrefslogtreecommitdiff
path: root/core
diff options
context:
space:
mode:
Diffstat (limited to 'core')
-rw-r--r--core/dvector.h2
-rw-r--r--core/global_constants.cpp4
-rw-r--r--core/io/http_client.cpp36
-rw-r--r--core/io/http_client.h1
-rw-r--r--core/io/multiplayer_api.cpp7
-rw-r--r--core/io/multiplayer_api.h2
-rw-r--r--core/io/stream_peer_ssl.cpp17
-rw-r--r--core/io/stream_peer_ssl.h8
-rw-r--r--core/os/input_event.cpp12
-rw-r--r--core/os/input_event.h5
-rw-r--r--core/os/os.cpp3
-rw-r--r--core/project_settings.cpp10
-rw-r--r--core/project_settings.h2
-rw-r--r--core/script_language.cpp77
-rw-r--r--core/script_language.h23
-rw-r--r--core/typedefs.h7
-rw-r--r--core/ustring.cpp40
17 files changed, 216 insertions, 40 deletions
diff --git a/core/dvector.h b/core/dvector.h
index c0190fb9e3..e03a755e6c 100644
--- a/core/dvector.h
+++ b/core/dvector.h
@@ -150,7 +150,7 @@ class PoolVector {
}
if (old_alloc->refcount.unref() == true) {
- //this should never happen but..
+ //this should never happen but..
#ifdef DEBUG_ENABLED
MemoryPool::alloc_mutex->lock();
diff --git a/core/global_constants.cpp b/core/global_constants.cpp
index 04810afe73..5b4dd05dbf 100644
--- a/core/global_constants.cpp
+++ b/core/global_constants.cpp
@@ -378,6 +378,8 @@ void register_global_constants() {
BIND_GLOBAL_ENUM_CONSTANT(BUTTON_LEFT);
BIND_GLOBAL_ENUM_CONSTANT(BUTTON_RIGHT);
BIND_GLOBAL_ENUM_CONSTANT(BUTTON_MIDDLE);
+ BIND_GLOBAL_ENUM_CONSTANT(BUTTON_XBUTTON1);
+ BIND_GLOBAL_ENUM_CONSTANT(BUTTON_XBUTTON2);
BIND_GLOBAL_ENUM_CONSTANT(BUTTON_WHEEL_UP);
BIND_GLOBAL_ENUM_CONSTANT(BUTTON_WHEEL_DOWN);
BIND_GLOBAL_ENUM_CONSTANT(BUTTON_WHEEL_LEFT);
@@ -385,6 +387,8 @@ void register_global_constants() {
BIND_GLOBAL_ENUM_CONSTANT(BUTTON_MASK_LEFT);
BIND_GLOBAL_ENUM_CONSTANT(BUTTON_MASK_RIGHT);
BIND_GLOBAL_ENUM_CONSTANT(BUTTON_MASK_MIDDLE);
+ BIND_GLOBAL_ENUM_CONSTANT(BUTTON_MASK_XBUTTON1);
+ BIND_GLOBAL_ENUM_CONSTANT(BUTTON_MASK_XBUTTON2);
//joypads
BIND_GLOBAL_ENUM_CONSTANT(JOY_BUTTON_0);
diff --git a/core/io/http_client.cpp b/core/io/http_client.cpp
index fcbb22b5de..f1620f1493 100644
--- a/core/io/http_client.cpp
+++ b/core/io/http_client.cpp
@@ -279,6 +279,7 @@ void HTTPClient::close() {
chunk_left = 0;
read_until_eof = false;
response_num = 0;
+ handshaking = false;
}
Error HTTPClient::poll() {
@@ -327,16 +328,40 @@ Error HTTPClient::poll() {
} break;
case StreamPeerTCP::STATUS_CONNECTED: {
if (ssl) {
- Ref<StreamPeerSSL> ssl = StreamPeerSSL::create();
- Error err = ssl->connect_to_stream(tcp_connection, ssl_verify_host, conn_host);
- if (err != OK) {
+ Ref<StreamPeerSSL> ssl;
+ if (!handshaking) {
+ // Connect the StreamPeerSSL and start handshaking
+ ssl = Ref<StreamPeerSSL>(StreamPeerSSL::create());
+ ssl->set_blocking_handshake_enabled(false);
+ Error err = ssl->connect_to_stream(tcp_connection, ssl_verify_host, conn_host);
+ if (err != OK) {
+ close();
+ status = STATUS_SSL_HANDSHAKE_ERROR;
+ return ERR_CANT_CONNECT;
+ }
+ connection = ssl;
+ handshaking = true;
+ } else {
+ // We are already handshaking, which means we can use your already active SSL connection
+ ssl = static_cast<Ref<StreamPeerSSL> >(connection);
+ ssl->poll(); // Try to finish the handshake
+ }
+
+ if (ssl->get_status() == StreamPeerSSL::STATUS_CONNECTED) {
+ // Handshake has been successfull
+ handshaking = false;
+ status = STATUS_CONNECTED;
+ return OK;
+ } else if (ssl->get_status() != StreamPeerSSL::STATUS_HANDSHAKING) {
+ // Handshake has failed
close();
status = STATUS_SSL_HANDSHAKE_ERROR;
return ERR_CANT_CONNECT;
}
- connection = ssl;
+ // ... we will need to poll more for handshake to finish
+ } else {
+ status = STATUS_CONNECTED;
}
- status = STATUS_CONNECTED;
return OK;
} break;
case StreamPeerTCP::STATUS_ERROR:
@@ -669,6 +694,7 @@ HTTPClient::HTTPClient() {
response_num = 0;
ssl = false;
blocking = false;
+ handshaking = false;
read_chunk_size = 4096;
}
diff --git a/core/io/http_client.h b/core/io/http_client.h
index 38ec82ce8c..82b56b01db 100644
--- a/core/io/http_client.h
+++ b/core/io/http_client.h
@@ -165,6 +165,7 @@ private:
bool ssl;
bool ssl_verify_host;
bool blocking;
+ bool handshaking;
Vector<uint8_t> response_str;
diff --git a/core/io/multiplayer_api.cpp b/core/io/multiplayer_api.cpp
index 846c89510e..ffd3ecaed0 100644
--- a/core/io/multiplayer_api.cpp
+++ b/core/io/multiplayer_api.cpp
@@ -704,7 +704,7 @@ void MultiplayerAPI::rsetp(Node *p_node, int p_peer_id, bool p_unreliable, const
_send_rpc(p_node, p_peer_id, p_unreliable, true, p_property, &vptr, 1);
}
-Error MultiplayerAPI::send_bytes(PoolVector<uint8_t> p_data, int p_to) {
+Error MultiplayerAPI::send_bytes(PoolVector<uint8_t> p_data, int p_to, NetworkedMultiplayerPeer::TransferMode p_mode) {
ERR_FAIL_COND_V(p_data.size() < 1, ERR_INVALID_DATA);
ERR_FAIL_COND_V(!network_peer.is_valid(), ERR_UNCONFIGURED);
@@ -714,7 +714,10 @@ Error MultiplayerAPI::send_bytes(PoolVector<uint8_t> p_data, int p_to) {
PoolVector<uint8_t>::Read r = p_data.read();
packet_cache[0] = NETWORK_COMMAND_RAW;
memcpy(&packet_cache[1], &r[0], p_data.size());
+
network_peer->set_target_peer(p_to);
+ network_peer->set_transfer_mode(p_mode);
+
return network_peer->put_packet(packet_cache.ptr(), p_data.size() + 1);
}
@@ -770,7 +773,7 @@ Vector<int> MultiplayerAPI::get_network_connected_peers() const {
void MultiplayerAPI::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_root_node", "node"), &MultiplayerAPI::set_root_node);
- ClassDB::bind_method(D_METHOD("send_bytes", "bytes", "id"), &MultiplayerAPI::send_bytes, DEFVAL(NetworkedMultiplayerPeer::TARGET_PEER_BROADCAST));
+ ClassDB::bind_method(D_METHOD("send_bytes", "bytes", "id"), &MultiplayerAPI::send_bytes, DEFVAL(NetworkedMultiplayerPeer::TARGET_PEER_BROADCAST), DEFVAL(NetworkedMultiplayerPeer::TRANSFER_MODE_RELIABLE));
ClassDB::bind_method(D_METHOD("has_network_peer"), &MultiplayerAPI::has_network_peer);
ClassDB::bind_method(D_METHOD("get_network_peer"), &MultiplayerAPI::get_network_peer);
ClassDB::bind_method(D_METHOD("get_network_unique_id"), &MultiplayerAPI::get_network_unique_id);
diff --git a/core/io/multiplayer_api.h b/core/io/multiplayer_api.h
index ef56c4c7f2..e47b1830e8 100644
--- a/core/io/multiplayer_api.h
+++ b/core/io/multiplayer_api.h
@@ -104,7 +104,7 @@ public:
void set_root_node(Node *p_node);
void set_network_peer(const Ref<NetworkedMultiplayerPeer> &p_peer);
Ref<NetworkedMultiplayerPeer> get_network_peer() const;
- Error send_bytes(PoolVector<uint8_t> p_data, int p_to = NetworkedMultiplayerPeer::TARGET_PEER_BROADCAST);
+ Error send_bytes(PoolVector<uint8_t> p_data, int p_to = NetworkedMultiplayerPeer::TARGET_PEER_BROADCAST, NetworkedMultiplayerPeer::TransferMode p_mode = NetworkedMultiplayerPeer::TRANSFER_MODE_RELIABLE);
// Called by Node.rpc
void rpcp(Node *p_node, int p_peer_id, bool p_unreliable, const StringName &p_method, const Variant **p_arg, int p_argcount);
diff --git a/core/io/stream_peer_ssl.cpp b/core/io/stream_peer_ssl.cpp
index 012ba78c6d..c71af6b641 100644
--- a/core/io/stream_peer_ssl.cpp
+++ b/core/io/stream_peer_ssl.cpp
@@ -52,6 +52,14 @@ bool StreamPeerSSL::is_available() {
return available;
}
+void StreamPeerSSL::set_blocking_handshake_enabled(bool p_enabled) {
+ blocking_handshake = p_enabled;
+}
+
+bool StreamPeerSSL::is_blocking_handshake_enabled() const {
+ return blocking_handshake;
+}
+
PoolByteArray StreamPeerSSL::get_project_cert_array() {
PoolByteArray out;
@@ -84,16 +92,21 @@ PoolByteArray StreamPeerSSL::get_project_cert_array() {
void StreamPeerSSL::_bind_methods() {
ClassDB::bind_method(D_METHOD("poll"), &StreamPeerSSL::poll);
- ClassDB::bind_method(D_METHOD("accept_stream", "stream"), &StreamPeerSSL::accept_stream);
+ ClassDB::bind_method(D_METHOD("accept_stream"), &StreamPeerSSL::accept_stream);
ClassDB::bind_method(D_METHOD("connect_to_stream", "stream", "validate_certs", "for_hostname"), &StreamPeerSSL::connect_to_stream, DEFVAL(false), DEFVAL(String()));
ClassDB::bind_method(D_METHOD("get_status"), &StreamPeerSSL::get_status);
ClassDB::bind_method(D_METHOD("disconnect_from_stream"), &StreamPeerSSL::disconnect_from_stream);
+ ClassDB::bind_method(D_METHOD("set_blocking_handshake_enabled", "enabled"), &StreamPeerSSL::set_blocking_handshake_enabled);
+ ClassDB::bind_method(D_METHOD("is_blocking_handshake_enabled"), &StreamPeerSSL::is_blocking_handshake_enabled);
+
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "blocking_handshake"), "set_blocking_handshake_enabled", "is_blocking_handshake_enabled");
BIND_ENUM_CONSTANT(STATUS_DISCONNECTED);
BIND_ENUM_CONSTANT(STATUS_CONNECTED);
- BIND_ENUM_CONSTANT(STATUS_ERROR_NO_CERTIFICATE);
+ BIND_ENUM_CONSTANT(STATUS_ERROR);
BIND_ENUM_CONSTANT(STATUS_ERROR_HOSTNAME_MISMATCH);
}
StreamPeerSSL::StreamPeerSSL() {
+ blocking_handshake = true;
}
diff --git a/core/io/stream_peer_ssl.h b/core/io/stream_peer_ssl.h
index 77301a7c87..870704e875 100644
--- a/core/io/stream_peer_ssl.h
+++ b/core/io/stream_peer_ssl.h
@@ -49,14 +49,20 @@ protected:
friend class Main;
static bool initialize_certs;
+ bool blocking_handshake;
+
public:
enum Status {
STATUS_DISCONNECTED,
+ STATUS_HANDSHAKING,
STATUS_CONNECTED,
- STATUS_ERROR_NO_CERTIFICATE,
+ STATUS_ERROR,
STATUS_ERROR_HOSTNAME_MISMATCH
};
+ void set_blocking_handshake_enabled(bool p_enabled);
+ bool is_blocking_handshake_enabled() const;
+
virtual void poll() = 0;
virtual Error accept_stream(Ref<StreamPeer> p_base) = 0;
virtual Error connect_to_stream(Ref<StreamPeer> p_base, bool p_validate_certs = false, const String &p_for_hostname = String()) = 0;
diff --git a/core/os/input_event.cpp b/core/os/input_event.cpp
index 4ebb821a2f..ca6446d015 100644
--- a/core/os/input_event.cpp
+++ b/core/os/input_event.cpp
@@ -509,6 +509,12 @@ String InputEventMouseButton::as_text() const {
case BUTTON_WHEEL_RIGHT:
button_index_string = "BUTTON_WHEEL_RIGHT";
break;
+ case BUTTON_XBUTTON1:
+ button_index_string = "BUTTON_XBUTTON1";
+ break;
+ case BUTTON_XBUTTON2:
+ button_index_string = "BUTTON_XBUTTON2";
+ break;
default:
button_index_string = itos(get_button_index());
break;
@@ -601,6 +607,12 @@ String InputEventMouseMotion::as_text() const {
case BUTTON_MASK_RIGHT:
button_mask_string = "BUTTON_MASK_RIGHT";
break;
+ case BUTTON_MASK_XBUTTON1:
+ button_mask_string = "BUTTON_MASK_XBUTTON1";
+ break;
+ case BUTTON_MASK_XBUTTON2:
+ button_mask_string = "BUTTON_MASK_XBUTTON2";
+ break;
default:
button_mask_string = itos(get_button_mask());
break;
diff --git a/core/os/input_event.h b/core/os/input_event.h
index 037649ed60..bd1a85ce29 100644
--- a/core/os/input_event.h
+++ b/core/os/input_event.h
@@ -53,10 +53,13 @@ enum ButtonList {
BUTTON_WHEEL_DOWN = 5,
BUTTON_WHEEL_LEFT = 6,
BUTTON_WHEEL_RIGHT = 7,
+ BUTTON_XBUTTON1 = 8,
+ BUTTON_XBUTTON2 = 9,
BUTTON_MASK_LEFT = (1 << (BUTTON_LEFT - 1)),
BUTTON_MASK_RIGHT = (1 << (BUTTON_RIGHT - 1)),
BUTTON_MASK_MIDDLE = (1 << (BUTTON_MIDDLE - 1)),
-
+ BUTTON_MASK_XBUTTON1 = (1 << (BUTTON_XBUTTON1 - 1)),
+ BUTTON_MASK_XBUTTON2 = (1 << (BUTTON_XBUTTON2 - 1))
};
enum JoystickList {
diff --git a/core/os/os.cpp b/core/os/os.cpp
index 5eed10e30c..d0a7bc6fbe 100644
--- a/core/os/os.cpp
+++ b/core/os/os.cpp
@@ -614,6 +614,9 @@ bool OS::has_feature(const String &p_feature) {
if (_check_internal_feature_support(p_feature))
return true;
+ if (ProjectSettings::get_singleton()->has_custom_feature(p_feature))
+ return true;
+
return false;
}
diff --git a/core/project_settings.cpp b/core/project_settings.cpp
index 7f9f4b638a..db1d0a604c 100644
--- a/core/project_settings.cpp
+++ b/core/project_settings.cpp
@@ -515,7 +515,11 @@ Error ProjectSettings::_load_settings_text(const String p_path) {
}
} else {
// config_version is checked and dropped
- set(section + "/" + assign, value);
+ if (section == String()) {
+ set(assign, value);
+ } else {
+ set(section + "/" + assign, value);
+ }
}
} else if (next_tag.name != String()) {
section = next_tag.name;
@@ -908,6 +912,10 @@ Variant ProjectSettings::get_setting(const String &p_setting) const {
return get(p_setting);
}
+bool ProjectSettings::has_custom_feature(const String &p_feature) const {
+ return custom_features.has(p_feature);
+}
+
void ProjectSettings::_bind_methods() {
ClassDB::bind_method(D_METHOD("has_setting", "name"), &ProjectSettings::has_setting);
diff --git a/core/project_settings.h b/core/project_settings.h
index 66f3ed954e..045d942b31 100644
--- a/core/project_settings.h
+++ b/core/project_settings.h
@@ -151,6 +151,8 @@ public:
void set_registering_order(bool p_enable);
+ bool has_custom_feature(const String &p_feature) const;
+
ProjectSettings();
~ProjectSettings();
};
diff --git a/core/script_language.cpp b/core/script_language.cpp
index acbe3b34db..37ba3cfc62 100644
--- a/core/script_language.cpp
+++ b/core/script_language.cpp
@@ -29,6 +29,7 @@
/*************************************************************************/
#include "script_language.h"
+#include "project_settings.h"
ScriptLanguage *ScriptServer::_languages[MAX_LANGUAGES];
int ScriptServer::_language_count = 0;
@@ -103,6 +104,20 @@ void ScriptServer::unregister_language(ScriptLanguage *p_language) {
void ScriptServer::init_languages() {
+ { //load global classes
+ global_classes_clear();
+ if (ProjectSettings::get_singleton()->has_setting("_global_script_classes")) {
+ Array script_classes = ProjectSettings::get_singleton()->get("_global_script_classes");
+
+ for (int i = 0; i < script_classes.size(); i++) {
+ Dictionary c = script_classes[i];
+ if (!c.has("class") || !c.has("language") || !c.has("path") || !c.has("base"))
+ continue;
+ add_global_class(c["class"], c["base"], c["language"], c["path"]);
+ }
+ }
+ }
+
for (int i = 0; i < _language_count; i++) {
_languages[i]->init();
}
@@ -113,6 +128,7 @@ void ScriptServer::finish_languages() {
for (int i = 0; i < _language_count; i++) {
_languages[i]->finish();
}
+ global_classes_clear();
}
void ScriptServer::set_reload_scripts_on_save(bool p_enable) {
@@ -139,6 +155,67 @@ void ScriptServer::thread_exit() {
}
}
+HashMap<StringName, ScriptServer::GlobalScriptClass> ScriptServer::global_classes;
+
+void ScriptServer::global_classes_clear() {
+ global_classes.clear();
+}
+
+void ScriptServer::add_global_class(const StringName &p_class, const StringName &p_base, const StringName &p_language, const String &p_path) {
+ GlobalScriptClass g;
+ g.language = p_language;
+ g.path = p_path;
+ g.base = p_base;
+ global_classes[p_class] = g;
+}
+void ScriptServer::remove_global_class(const StringName &p_class) {
+ global_classes.erase(p_class);
+}
+bool ScriptServer::is_global_class(const StringName &p_class) {
+ return global_classes.has(p_class);
+}
+StringName ScriptServer::get_global_class_language(const StringName &p_class) {
+ ERR_FAIL_COND_V(!global_classes.has(p_class), StringName());
+ return global_classes[p_class].language;
+}
+String ScriptServer::get_global_class_path(const String &p_class) {
+ ERR_FAIL_COND_V(!global_classes.has(p_class), String());
+ return global_classes[p_class].path;
+}
+
+StringName ScriptServer::get_global_class_base(const String &p_class) {
+ ERR_FAIL_COND_V(!global_classes.has(p_class), String());
+ return global_classes[p_class].base;
+}
+void ScriptServer::get_global_class_list(List<StringName> *r_global_classes) {
+ const StringName *K = NULL;
+ List<StringName> classes;
+ while ((K = global_classes.next(K))) {
+ classes.push_back(*K);
+ }
+ classes.sort_custom<StringName::AlphCompare>();
+ for (List<StringName>::Element *E = classes.front(); E; E = E->next()) {
+ r_global_classes->push_back(E->get());
+ }
+}
+void ScriptServer::save_global_classes() {
+ List<StringName> gc;
+ get_global_class_list(&gc);
+ Array gcarr;
+ for (List<StringName>::Element *E = gc.front(); E; E = E->next()) {
+ Dictionary d;
+ d["class"] = E->get();
+ d["language"] = global_classes[E->get()].language;
+ d["path"] = global_classes[E->get()].path;
+ d["base"] = global_classes[E->get()].base;
+ gcarr.push_back(d);
+ }
+
+ ProjectSettings::get_singleton()->set("_global_script_classes", gcarr);
+ ProjectSettings::get_singleton()->save();
+}
+
+////////////////////
void ScriptInstance::get_property_state(List<Pair<StringName, Variant> > &state) {
List<PropertyInfo> pinfo;
diff --git a/core/script_language.h b/core/script_language.h
index e7748f93e2..2950b35109 100644
--- a/core/script_language.h
+++ b/core/script_language.h
@@ -54,6 +54,14 @@ class ScriptServer {
static bool scripting_enabled;
static bool reload_scripts_on_save;
+ struct GlobalScriptClass {
+ StringName language;
+ String path;
+ String base;
+ };
+
+ static HashMap<StringName, GlobalScriptClass> global_classes;
+
public:
static ScriptEditRequestFunction edit_request_func;
@@ -70,6 +78,16 @@ public:
static void thread_enter();
static void thread_exit();
+ static void global_classes_clear();
+ static void add_global_class(const StringName &p_class, const StringName &p_base, const StringName &p_language, const String &p_path);
+ static void remove_global_class(const StringName &p_class);
+ static bool is_global_class(const StringName &p_class);
+ static StringName get_global_class_language(const StringName &p_class);
+ static String get_global_class_path(const String &p_class);
+ static StringName get_global_class_base(const String &p_class);
+ static void get_global_class_list(List<StringName> *r_global_classes);
+ static void save_global_classes();
+
static void init_languages();
static void finish_languages();
};
@@ -285,7 +303,10 @@ public:
virtual void frame();
- virtual ~ScriptLanguage(){};
+ virtual bool handles_global_class_type(const String &p_type) const { return false; }
+ virtual String get_global_class_name(const String &p_path, String *r_base_type = NULL) const { return String(); }
+
+ virtual ~ScriptLanguage() {}
};
extern uint8_t script_encryption_key[32];
diff --git a/core/typedefs.h b/core/typedefs.h
index 4758a5408d..71771ea4e6 100644
--- a/core/typedefs.h
+++ b/core/typedefs.h
@@ -74,7 +74,7 @@ T *_nullptr() {
#define OFFSET_OF(st, m) \
((size_t)((char *)&(_nullptr<st>()->m) - (char *)0))
- /**
+/**
* Some platforms (devices) not define NULL
*/
@@ -82,7 +82,7 @@ T *_nullptr() {
#define NULL 0
#endif
- /**
+/**
* Windows defines a lot of badly stuff we'll never ever use. undefine it.
*/
@@ -97,6 +97,7 @@ T *_nullptr() {
#undef CLAMP // override standard definition
#undef Error
#undef OK
+#undef CONNECT_DEFERRED // override from Windows SDK, clashes with Object enum
#endif
#include "int_types.h"
@@ -104,7 +105,7 @@ T *_nullptr() {
#include "error_list.h"
#include "error_macros.h"
- /** Generic ABS function, for math uses please use Math::abs */
+/** Generic ABS function, for math uses please use Math::abs */
#ifndef ABS
#define ABS(m_v) ((m_v < 0) ? (-(m_v)) : (m_v))
diff --git a/core/ustring.cpp b/core/ustring.cpp
index 51f05468e2..bee5f5ffdb 100644
--- a/core/ustring.cpp
+++ b/core/ustring.cpp
@@ -757,36 +757,32 @@ Vector<String> String::rsplit(const String &p_splitter, bool p_allow_empty, int
Vector<String> ret;
const int len = length();
- int from = len;
+ int remaining_len = len;
while (true) {
- int end = rfind(p_splitter, from);
- if (end < 0)
- end = 0;
-
- if (p_allow_empty || (end < from)) {
- const String str = substr(end > 0 ? end + p_splitter.length() : end, end > 0 ? from - end : from + 2);
-
- if (p_maxsplit <= 0) {
- ret.push_back(str);
- } else if (p_maxsplit > 0) {
-
- // Put rest of the string and leave cycle.
- if (p_maxsplit == ret.size()) {
- ret.push_back(substr(0, from + 2));
- break;
- }
-
- // Otherwise, push items until positive limit is reached.
- ret.push_back(str);
+ if (remaining_len < p_splitter.length() || (p_maxsplit > 0 && p_maxsplit == ret.size())) {
+ // no room for another splitter or hit max splits, push what's left and we're done
+ if (p_allow_empty || remaining_len > 0) {
+ ret.push_back(substr(0, remaining_len));
}
+ break;
}
- if (end == 0)
+ int left_edge = rfind(p_splitter, remaining_len - p_splitter.length());
+
+ if (left_edge < 0) {
+ // no more splitters, we're done
+ ret.push_back(substr(0, remaining_len));
break;
+ }
+
+ int substr_start = left_edge + p_splitter.length();
+ if (p_allow_empty || substr_start < remaining_len) {
+ ret.push_back(substr(substr_start, remaining_len - substr_start));
+ }
- from = end - p_splitter.length();
+ remaining_len = left_edge;
}
ret.invert();