diff --git a/bin/tests/test_string.cpp b/bin/tests/test_string.cpp index 3c8d0f7d86d..93b1835b785 100644 --- a/bin/tests/test_string.cpp +++ b/bin/tests/test_string.cpp @@ -31,7 +31,7 @@ //#include "math_funcs.h" #include #include "os/os.h" -#include "drivers/trex/regex.h" +#include "drivers/nrex/regex.h" #include "test_string.h" @@ -463,20 +463,16 @@ bool test_26() { OS::get_singleton()->print("\n\nTest 26: RegEx\n"); RegEx regexp("(.*):(.*)"); - List captures; - bool match = regexp.match("name:password", &captures); - printf("\tmatch: %s\n", match?"true":"false"); + int res = regexp.find("name:password"); + printf("\tmatch: %s\n", (res>=0)?"true":"false"); - printf("\t%i captures:\n", captures.size()); - List::Element *I = captures.front(); - while (I) { - - printf("%ls\n", I->get().c_str()); - - I = I->next(); - }; - return captures.size(); + printf("\t%i captures:\n", regexp.get_capture_count()); + for (int i = 0; i &p_arr) { + + int len = p_arr.size(); + DVector::Read r = p_arr.read(); + + int b64len = len / 3 * 4 + 4 + 1; + DVector b64buff; + b64buff.resize(b64len); + DVector::Write w64 = b64buff.write(); + + int strlen = base64_encode((char*)(&w64[0]), (char*)(&r[0]), len); + w64[strlen] = 0; + String ret = (char*)&w64[0]; + + return ret; +}; + +DVector _Marshalls::base64_to_raw(const String &p_str) { + + int strlen = p_str.length(); + CharString cstr = p_str.ascii(); + + int arr_len; + DVector buf; + { + buf.resize(strlen / 4 * 3 + 1); + DVector::Write w = buf.write(); + + arr_len = base64_decode((char*)(&w[0]), (char*)cstr.get_data(), strlen); + }; + buf.resize(arr_len); + + // conversion from DVector to raw array? + return buf; +}; + +String _Marshalls::utf8_to_base64(const String& p_str) { + + CharString cstr = p_str.utf8(); + int len = cstr.length(); + + int b64len = len / 3 * 4 + 4 + 1; + DVector b64buff; + b64buff.resize(b64len); + DVector::Write w64 = b64buff.write(); + + int strlen = base64_encode((char*)(&w64[0]), (char*)cstr.get_data(), len); + + w64[strlen] = 0; + String ret = (char*)&w64[0]; + + return ret; +}; + +String _Marshalls::base64_to_utf8(const String& p_str) { + + int strlen = p_str.length(); + CharString cstr = p_str.ascii(); + + DVector buf; + buf.resize(strlen / 4 * 3 + 1 + 1); + DVector::Write w = buf.write(); + + int len = base64_decode((char*)(&w[0]), (char*)cstr.get_data(), strlen); + + w[len] = 0; + String ret = String::utf8((char*)&w[0]); + + return ret; +}; + void _Marshalls::_bind_methods() { ObjectTypeDB::bind_method(_MD("variant_to_base64:String","variant"),&_Marshalls::variant_to_base64); ObjectTypeDB::bind_method(_MD("base64_to_variant:Variant","base64_str"),&_Marshalls::base64_to_variant); + ObjectTypeDB::bind_method(_MD("raw_to_base64:String","array"),&_Marshalls::raw_to_base64); + ObjectTypeDB::bind_method(_MD("base64_to_raw:RawArray","base64_str"),&_Marshalls::base64_to_raw); + + ObjectTypeDB::bind_method(_MD("utf8_to_base64:String","utf8_str"),&_Marshalls::utf8_to_base64); + ObjectTypeDB::bind_method(_MD("base64_to_utf8:String","base64_str"),&_Marshalls::base64_to_utf8); + }; diff --git a/core/bind/core_bind.h b/core/bind/core_bind.h index 74f29c23e86..83f9e533eab 100644 --- a/core/bind/core_bind.h +++ b/core/bind/core_bind.h @@ -436,6 +436,12 @@ public: String variant_to_base64(const Variant& p_var); Variant base64_to_variant(const String& p_str); + String raw_to_base64(const DVector& p_arr); + DVector base64_to_raw(const String& p_str); + + String utf8_to_base64(const String& p_str); + String base64_to_utf8(const String& p_str); + _Marshalls() {}; }; diff --git a/core/script_debugger_remote.cpp b/core/script_debugger_remote.cpp index 33e9dc0fd98..15be8b1d002 100644 --- a/core/script_debugger_remote.cpp +++ b/core/script_debugger_remote.cpp @@ -127,7 +127,7 @@ void ScriptDebuggerRemote::debug(ScriptLanguage *p_script,bool p_can_continue) { ERR_CONTINUE( cmd[0].get_type()!=Variant::STRING ); String command = cmd[0]; - cmd.remove(0); + if (command=="get_stack_dump") { @@ -150,7 +150,7 @@ void ScriptDebuggerRemote::debug(ScriptLanguage *p_script,bool p_can_continue) { } else if (command=="get_stack_frame_vars") { - + cmd.remove(0); ERR_CONTINUE( cmd.size()!=1 ); int lv = cmd[0]; @@ -243,6 +243,8 @@ void ScriptDebuggerRemote::debug(ScriptLanguage *p_script,bool p_can_continue) { if (request_scene_tree) request_scene_tree(request_scene_tree_ud); + } else { + _parse_live_edit(cmd); } @@ -301,6 +303,105 @@ void ScriptDebuggerRemote::line_poll() { } +bool ScriptDebuggerRemote::_parse_live_edit(const Array& cmd) { + + String cmdstr = cmd[0]; + if (!live_edit_funcs || !cmdstr.begins_with("live_")) + return false; + + + //print_line(Variant(cmd).get_construct_string()); + if (cmdstr=="live_set_root") { + + if (!live_edit_funcs->root_func) + return true; + //print_line("root: "+Variant(cmd).get_construct_string()); + live_edit_funcs->root_func(live_edit_funcs->udata,cmd[1],cmd[2]); + + } else if (cmdstr=="live_node_path") { + + if (!live_edit_funcs->node_path_func) + return true; + //print_line("path: "+Variant(cmd).get_construct_string()); + + live_edit_funcs->node_path_func(live_edit_funcs->udata,cmd[1],cmd[2]); + + } else if (cmdstr=="live_res_path") { + + if (!live_edit_funcs->res_path_func) + return true; + live_edit_funcs->res_path_func(live_edit_funcs->udata,cmd[1],cmd[2]); + + } else if (cmdstr=="live_node_prop_res") { + if (!live_edit_funcs->node_set_res_func) + return true; + + live_edit_funcs->node_set_res_func(live_edit_funcs->udata,cmd[1],cmd[2],cmd[3]); + + } else if (cmdstr=="live_node_prop") { + + if (!live_edit_funcs->node_set_func) + return true; + live_edit_funcs->node_set_func(live_edit_funcs->udata,cmd[1],cmd[2],cmd[3]); + + } else if (cmdstr=="live_res_prop_res") { + + if (!live_edit_funcs->res_set_res_func) + return true; + live_edit_funcs->res_set_res_func(live_edit_funcs->udata,cmd[1],cmd[2],cmd[3]); + + } else if (cmdstr=="live_res_prop") { + + if (!live_edit_funcs->res_set_func) + return true; + live_edit_funcs->res_set_func(live_edit_funcs->udata,cmd[1],cmd[2],cmd[3]); + + } else if (cmdstr=="live_node_call") { + + if (!live_edit_funcs->node_call_func) + return true; + live_edit_funcs->node_call_func(live_edit_funcs->udata,cmd[1],cmd[2], cmd[3],cmd[4],cmd[5],cmd[6],cmd[7]); + + } else if (cmdstr=="live_res_call") { + + if (!live_edit_funcs->res_call_func) + return true; + live_edit_funcs->res_call_func(live_edit_funcs->udata,cmd[1],cmd[2], cmd[3],cmd[4],cmd[5],cmd[6],cmd[7]); + + } else if (cmdstr=="live_create_node") { + + live_edit_funcs->tree_create_node_func(live_edit_funcs->udata,cmd[1],cmd[2],cmd[3]); + + } else if (cmdstr=="live_instance_node") { + + live_edit_funcs->tree_instance_node_func(live_edit_funcs->udata,cmd[1],cmd[2],cmd[3]); + + } else if (cmdstr=="live_remove_node") { + + live_edit_funcs->tree_remove_node_func(live_edit_funcs->udata,cmd[1]); + + } else if (cmdstr=="live_remove_and_keep_node") { + + live_edit_funcs->tree_remove_and_keep_node_func(live_edit_funcs->udata,cmd[1],cmd[2]); + } else if (cmdstr=="live_restore_node") { + + live_edit_funcs->tree_restore_node_func(live_edit_funcs->udata,cmd[1],cmd[2],cmd[3]); + + } else if (cmdstr=="live_duplicate_node") { + + live_edit_funcs->tree_duplicate_node_func(live_edit_funcs->udata,cmd[1],cmd[2]); + } else if (cmdstr=="live_reparent_node") { + + live_edit_funcs->tree_reparent_node_func(live_edit_funcs->udata,cmd[1],cmd[2],cmd[3],cmd[4]); + + } else { + + return false; + } + + return true; +} + void ScriptDebuggerRemote::_poll_events() { while(packet_peer_stream->get_available_packet_count()>0) { @@ -321,7 +422,7 @@ void ScriptDebuggerRemote::_poll_events() { ERR_CONTINUE( cmd[0].get_type()!=Variant::STRING ); String command = cmd[0]; - cmd.remove(0); + //cmd.remove(0); if (command=="break") { @@ -331,6 +432,8 @@ void ScriptDebuggerRemote::_poll_events() { if (request_scene_tree) request_scene_tree(request_scene_tree_ud); + } else { + _parse_live_edit(cmd); } } @@ -413,6 +516,11 @@ void ScriptDebuggerRemote::set_request_scene_tree_message_func(RequestSceneTreeM request_scene_tree_ud=p_udata; } +void ScriptDebuggerRemote::set_live_edit_funcs(LiveEditFuncs *p_funcs) { + + live_edit_funcs=p_funcs; +} + ScriptDebuggerRemote::ScriptDebuggerRemote() { tcp_client = StreamPeerTCP::create_ref(); @@ -429,6 +537,7 @@ ScriptDebuggerRemote::ScriptDebuggerRemote() { last_perf_time=0; poll_every=0; request_scene_tree=NULL; + live_edit_funcs=NULL; } diff --git a/core/script_debugger_remote.h b/core/script_debugger_remote.h index 89b9947c4b0..748b77eccd4 100644 --- a/core/script_debugger_remote.h +++ b/core/script_debugger_remote.h @@ -62,9 +62,12 @@ class ScriptDebuggerRemote : public ScriptDebugger { uint32_t poll_every; + bool _parse_live_edit(const Array &p_command); + RequestSceneTreeMessageFunc request_scene_tree; void *request_scene_tree_ud; + LiveEditFuncs *live_edit_funcs; public: @@ -79,6 +82,7 @@ public: virtual void send_message(const String& p_message, const Array& p_args); virtual void set_request_scene_tree_message_func(RequestSceneTreeMessageFunc p_func, void *p_udata); + virtual void set_live_edit_funcs(LiveEditFuncs *p_funcs); ScriptDebuggerRemote(); ~ScriptDebuggerRemote(); diff --git a/core/script_language.h b/core/script_language.h index 7104fe45473..d5fb83deb16 100644 --- a/core/script_language.h +++ b/core/script_language.h @@ -238,6 +238,32 @@ public: typedef void (*RequestSceneTreeMessageFunc)(void *); + struct LiveEditFuncs { + + void *udata; + void (*node_path_func)(void *,const NodePath &p_path,int p_id); + void (*res_path_func)(void *,const String &p_path,int p_id); + + void (*node_set_func)(void *,int p_id,const StringName& p_prop,const Variant& p_value); + void (*node_set_res_func)(void *,int p_id,const StringName& p_prop,const String& p_value); + void (*node_call_func)(void *,int p_id,const StringName& p_method,VARIANT_ARG_DECLARE); + void (*res_set_func)(void *,int p_id,const StringName& p_prop,const Variant& p_value); + void (*res_set_res_func)(void *,int p_id,const StringName& p_prop,const String& p_value); + void (*res_call_func)(void *,int p_id,const StringName& p_method,VARIANT_ARG_DECLARE); + void (*root_func)(void*, const NodePath& p_scene_path,const String& p_scene_from); + + void (*tree_create_node_func)(void*,const NodePath& p_parent,const String& p_type,const String& p_name); + void (*tree_instance_node_func)(void*,const NodePath& p_parent,const String& p_path,const String& p_name); + void (*tree_remove_node_func)(void*,const NodePath& p_at); + void (*tree_remove_and_keep_node_func)(void*,const NodePath& p_at,ObjectID p_keep_id); + void (*tree_restore_node_func)(void*,ObjectID p_id,const NodePath& p_at,int p_at_pos); + void (*tree_duplicate_node_func)(void*,const NodePath& p_at,const String& p_new_name); + void (*tree_reparent_node_func)(void*,const NodePath& p_at,const NodePath& p_new_place,const String& p_new_name,int p_at_pos); + + }; + + + _FORCE_INLINE_ static ScriptDebugger * get_singleton() { return singleton; } void set_lines_left(int p_left); int get_lines_left() const; @@ -252,10 +278,12 @@ public: bool is_breakpoint_line(int p_line) const; void clear_breakpoints(); + virtual void debug(ScriptLanguage *p_script,bool p_can_continue=true)=0; virtual void idle_poll(); virtual void line_poll(); + void set_break_language(ScriptLanguage *p_lang); ScriptLanguage* get_break_language() const; @@ -265,6 +293,7 @@ public: virtual void request_quit() {} virtual void set_request_scene_tree_message_func(RequestSceneTreeMessageFunc p_func, void *p_udata) {} + virtual void set_live_edit_funcs(LiveEditFuncs *p_funcs) {} ScriptDebugger(); virtual ~ScriptDebugger() {singleton=NULL;} diff --git a/core/undo_redo.cpp b/core/undo_redo.cpp index f565070216a..85cc2bbc7f8 100644 --- a/core/undo_redo.cpp +++ b/core/undo_redo.cpp @@ -244,7 +244,12 @@ void UndoRedo::_process_operation_list(List::Element *E) { Resource* res = obj->cast_to(); if (res) res->set_edited(true); + #endif + + if (method_callback) { + method_callback(method_callbck_ud,obj,op.name,VARIANT_ARGS_FROM_ARRAY(op.args)); + } } break; case Operation::TYPE_PROPERTY: { @@ -254,6 +259,9 @@ void UndoRedo::_process_operation_list(List::Element *E) { if (res) res->set_edited(true); #endif + if (property_callback) { + property_callback(prop_callback_ud,obj,op.name,op.args[0]); + } } break; case Operation::TYPE_REFERENCE: { //do nothing @@ -325,6 +333,19 @@ void UndoRedo::set_commit_notify_callback(CommitNotifyCallback p_callback,void* callback_ud=p_ud; } +void UndoRedo::set_method_notify_callback(MethodNotifyCallback p_method_callback,void* p_ud) { + + method_callback=p_method_callback; + method_callbck_ud=p_ud; +} + +void UndoRedo::set_property_notify_callback(PropertyNotifyCallback p_property_callback,void* p_ud){ + + property_callback=p_property_callback; + prop_callback_ud=p_ud; +} + + UndoRedo::UndoRedo() { version=1; @@ -334,6 +355,12 @@ UndoRedo::UndoRedo() { merging=true; callback=NULL; callback_ud=NULL; + + method_callbck_ud=NULL; + prop_callback_ud=NULL; + method_callback=NULL; + property_callback=NULL; + } UndoRedo::~UndoRedo() { diff --git a/core/undo_redo.h b/core/undo_redo.h index a9187534c14..141a413c2a8 100644 --- a/core/undo_redo.h +++ b/core/undo_redo.h @@ -45,6 +45,9 @@ public: Variant _add_do_method(const Variant** p_args, int p_argcount, Variant::CallError& r_error); Variant _add_undo_method(const Variant** p_args, int p_argcount, Variant::CallError& r_error); + typedef void (*MethodNotifyCallback)(void *p_ud,Object*p_base,const StringName& p_name,VARIANT_ARG_DECLARE); + typedef void (*PropertyNotifyCallback)(void *p_ud,Object*p_base,const StringName& p_property,const Variant& p_value); + private: struct Operation { @@ -83,6 +86,11 @@ private: CommitNotifyCallback callback; void* callback_ud; + void* method_callbck_ud; + void* prop_callback_ud; + + MethodNotifyCallback method_callback; + PropertyNotifyCallback property_callback; protected: @@ -113,6 +121,9 @@ public: void set_commit_notify_callback(CommitNotifyCallback p_callback,void* p_ud); + void set_method_notify_callback(MethodNotifyCallback p_method_callback,void* p_ud); + void set_property_notify_callback(PropertyNotifyCallback p_property_callback,void* p_ud); + UndoRedo(); ~UndoRedo(); }; diff --git a/demos/2d/platformer/player.xml b/demos/2d/platformer/player.xml index 196881dee43..8c7b74ceae1 100644 --- a/demos/2d/platformer/player.xml +++ b/demos/2d/platformer/player.xml @@ -1,15 +1,15 @@ - - + + + - - + - - - + + + 0.5 20 @@ -19,6 +19,11 @@ 0 -19.902, -24.8691, 19.3625, -24.6056, -0.138023, 16.5036 + + + 0, 1 + 1, 1, 1, 1, 0, 0, 0, 0.0442478 + "idle" @@ -31,6 +36,8 @@ "cont" False + "times" + 0, 1.25, 1.5, 2, 4.5, 4.75, 5, 5.25 "transitions" 1, 1, 1, 1, 1, 1, 1, 1 "values" @@ -44,8 +51,6 @@ 19 16 - "times" - 0, 1.25, 1.5, 2, 4.5, 4.75, 5, 5.25 @@ -60,6 +65,8 @@ "cont" False + "times" + 0, 0.25, 0.5 "transitions" 1, 1, 1 "values" @@ -68,8 +75,6 @@ 24 23 - "times" - 0, 0.25, 0.5 @@ -84,14 +89,14 @@ "cont" False + "times" + 0 "transitions" 1 "values" 25 - "times" - 0 @@ -105,6 +110,8 @@ "cont" False + "times" + 0, 0.25, 0.5, 0.75, 1, 1.25 "transitions" 1, 1, 1, 1, 1, 1 "values" @@ -116,56 +123,10 @@ 4 0 - "times" - 0, 0.25, 0.5, 0.75, 1, 1.25 - - "crouch" - 0.01 - True - 0.25 - "value" - "sprite:frame" - 1 - - "cont" - False - "transitions" - 1 - "values" - - 22 - - "times" - 0 - - - - - "falling" - 0.01 - True - 0.25 - "value" - "sprite:frame" - 1 - - "cont" - False - "transitions" - 1 - "values" - - 21 - - "times" - 0 - - - - + 1.25 True 0.25 @@ -175,19 +136,19 @@ "cont" False + "times" + 0, 0.25, 0.5, 0.75, 1, 1.25 "transitions" 1, 1, 1, 1, 1, 1 "values" - 10 - 11 - 12 - 13 - 14 + 5 + 6 + 7 + 8 + 9 5 - "times" - 0, 0.25, 0.5, 0.75, 1, 1.25 @@ -202,18 +163,62 @@ "cont" False + "times" + 0 "transitions" 1 "values" 26 - "times" - 0 - + + "crouch" + 0.01 + True + 0.25 + "value" + "sprite:frame" + 1 + + "cont" + False + "times" + 0 + "transitions" + 1 + "values" + + 22 + + + + + + "falling" + 0.01 + True + 0.25 + "value" + "sprite:frame" + 1 + + "cont" + False + "times" + 0 + "transitions" + 1 + "values" + + 21 + + + + + 1.25 True 0.25 @@ -223,19 +228,19 @@ "cont" False + "times" + 0, 0.25, 0.5, 0.75, 1, 1.25 "transitions" 1, 1, 1, 1, 1, 1 "values" - 5 - 6 - 7 - 8 - 9 + 10 + 11 + 12 + 13 + 14 5 - "times" - 0, 0.25, 0.5, 0.75, 1, 1.25 @@ -249,14 +254,14 @@ "cont" False + "times" + 0 "transitions" 1 "values" 26 - "times" - 0 @@ -289,30 +294,28 @@ + "conn_count" + 0 + "conns" + "names" - + "player" "RigidBody2D" - "_import_path" - "visibility/visible" - "visibility/opacity" - "visibility/self_opacity" - "visibility/behind_parent" - "transform/pos" - "transform/rot" - "transform/scale" - "shape_count" + "input/pickable" "shapes/0/shape" "shapes/0/transform" "shapes/0/trigger" "shapes/1/shape" "shapes/1/transform" "shapes/1/trigger" - "layers" + "collision/layers" + "collision/mask" "mode" "mass" "friction" "bounce" + "gravity_scale" "custom_integrator" "continuous_cd" "contacts_reported" @@ -321,39 +324,28 @@ "can_sleep" "velocity/linear" "velocity/angular" + "damp_override/linear" + "damp_override/angular" "script/script" "__meta__" "sprite" "Sprite" "texture" - "centered" - "offset" - "flip_h" - "flip_v" "vframes" "hframes" - "frame" - "modulate" - "region" - "region_rect" "smoke" "Particles2D" + "visibility/self_opacity" "visibility/blend_mode" + "transform/pos" + "transform/rot" "config/amount" "config/lifetime" - "config/time_scale" - "config/preprocess" "config/emit_timeout" "config/emitting" - "config/offset" - "config/half_extents" "config/local_space" "config/explosiveness" - "config/flip_h" - "config/flip_v" "config/texture" - "config/h_frames" - "config/v_frames" "params/direction" "params/spread" "params/linear_velocity" @@ -370,32 +362,8 @@ "params/hue_variation" "params/anim_speed_scale" "params/anim_initial_pos" - "randomness/direction" - "randomness/spread" - "randomness/linear_velocity" "randomness/spin_velocity" - "randomness/orbit_velocity" - "randomness/gravity_direction" - "randomness/gravity_strength" - "randomness/radial_accel" - "randomness/tangential_accel" - "randomness/damping" - "randomness/initial_angle" - "randomness/initial_size" - "randomness/final_size" - "randomness/hue_variation" - "randomness/anim_speed_scale" - "randomness/anim_initial_pos" - "color_phases/count" - "phase_0/pos" - "phase_0/color" - "phase_1/pos" - "phase_1/color" - "phase_2/pos" - "phase_2/color" - "phase_3/pos" - "phase_3/color" - "emission_points" + "color/color_ramp" "anim" "AnimationPlayer" "playback/process_mode" @@ -405,11 +373,11 @@ "anims/jumping" "anims/idle_weapon" "anims/run" + "anims/run_weapon" + "anims/falling_weapon" "anims/crouch" "anims/falling" "anims/standing_weapon_ready" - "anims/falling_weapon" - "anims/run_weapon" "anims/jumping_weapon" "playback/active" "playback/speed" @@ -417,6 +385,7 @@ "autoplay" "camera" "Camera2D" + "anchor_mode" "rotating" "current" "smoothing" @@ -434,6 +403,7 @@ "bullet_shoot" "Position2D" "CollisionShape2D" + "transform/scale" "shape" "trigger" "sound" @@ -458,6 +428,7 @@ "ui" "CanvasLayer" "layer" + "offset" "rotation" "scale" "left" @@ -472,147 +443,149 @@ "jump" "fire" - "version" - 1 - "conn_count" - 0 "node_count" 14 + "nodes" + -1, -1, 1, 0, -1, 26, 2, 0, 3, 1, 4, 2, 5, 0, 6, 3, 7, 4, 8, 0, 9, 5, 10, 5, 11, 6, 12, 7, 13, 8, 14, 8, 15, 9, 16, 10, 17, 11, 18, 12, 19, 0, 20, 0, 21, 10, 22, 13, 23, 8, 24, 14, 25, 14, 26, 15, 27, 16, 0, 0, 0, 29, 28, -1, 3, 30, 17, 31, 6, 32, 18, 0, 1, 0, 34, 33, -1, 29, 35, 19, 36, 5, 37, 20, 38, 21, 39, 22, 40, 23, 41, 23, 42, 0, 43, 0, 44, 24, 45, 25, 46, 8, 47, 26, 48, 27, 49, 9, 50, 8, 51, 8, 52, 28, 53, 8, 54, 8, 55, 8, 56, 8, 57, 29, 58, 29, 59, 8, 60, 9, 61, 8, 62, 29, 63, 30, 0, 0, 0, 65, 64, -1, 17, 66, 5, 67, 8, 68, 31, 69, 32, 70, 33, 71, 34, 72, 35, 73, 36, 74, 37, 75, 38, 76, 39, 77, 40, 78, 41, 79, 10, 80, 29, 81, 42, 82, 43, 0, 0, 0, 84, 83, -1, 15, 85, 5, 86, 0, 87, 10, 88, 8, 89, 44, 90, 11, 91, 11, 92, 45, 93, 45, 94, 10, 95, 10, 96, 46, 97, 46, 98, 46, 99, 46, 0, 0, 0, 101, 100, -1, 1, 37, 47, 0, 0, 0, 102, 102, -1, 4, 37, 48, 103, 49, 104, 1, 105, 0, 0, 0, 0, 107, 106, -1, 14, 108, 12, 109, 50, 110, 8, 111, 9, 112, 8, 113, 8, 114, 8, 115, 51, 116, 51, 117, 51, 118, 51, 119, 6, 120, 8, 121, 8, 0, 0, 0, 122, 122, -1, 3, 123, 11, 124, 52, 105, 0, 0, 0, 0, 126, 125, -1, 4, 127, 11, 128, 13, 129, 8, 130, 44, 0, 9, 0, 132, 131, -1, 8, 37, 53, 103, 54, 133, 55, 134, 56, 135, 56, 136, 10, 137, 57, 138, 5, 0, 9, 0, 132, 139, -1, 8, 37, 58, 103, 54, 133, 59, 134, 56, 135, 56, 136, 10, 137, 60, 138, 5, 0, 9, 0, 132, 140, -1, 8, 37, 61, 103, 54, 133, 62, 134, 56, 135, 56, 136, 0, 137, 63, 138, 5, 0, 9, 0, 132, 141, -1, 8, 37, 64, 103, 54, 133, 65, 134, 56, 135, 56, 136, 0, 137, 66, 138, 5, 0 "variants" - - "" - True - 1 + False - 0, 0 - 0 - 1, 1 - 2 1, -0, 0, 1.76469, 0.291992, -12.1587 1, -0, 0, 1, 0, 0 1 + 2 3 + 0 + 1 + True 0 3 + 0, 0 + -1 + "__editor_plugin_screen__" + "2D" "__editor_plugin_states__" - "Script" - - "current" - 0 - "sources" - - "res://player.gd" - - "2D" - "pixel_snap" - False - "zoom" - 2.272073 - "use_snap" - False "ofs" - -181.946, -86.2812 - "snap" - 10 + -110.795, -101.2 + "snap_grid" + False + "snap_offset" + 0, 0 + "snap_pixel" + False + "snap_relative" + False + "snap_rotation" + False + "snap_rotation_offset" + 0 + "snap_rotation_step" + 0.261799 + "snap_show_grid" + False + "snap_step" + 10, 10 + "zoom" + 2.050546 "3D" + "ambient_light_color" + 0.15, 0.15, 0.15, 1 + "default_light" + True + "default_srgb" + False + "deflight_rot_x" + 0.942478 "deflight_rot_y" 0.628319 - "zfar" - 500 "fov" 45 + "show_grid" + True + "show_origin" + True + "viewport_mode" + 1 "viewports" "distance" 4 - "x_rot" - 0 - "y_rot" - 0 "listener" True + "pos" + 0, 0, 0 "use_environment" False "use_orthogonal" False - "pos" - 0, 0, 0 - - - "distance" - 4 "x_rot" 0 "y_rot" 0 - "listener" - False - "use_environment" - False - "use_orthogonal" - False - "pos" - 0, 0, 0 "distance" 4 - "x_rot" - 0 - "y_rot" - 0 "listener" False + "pos" + 0, 0, 0 "use_environment" False "use_orthogonal" False - "pos" - 0, 0, 0 + "x_rot" + 0 + "y_rot" + 0 "distance" 4 - "x_rot" - 0 - "y_rot" - 0 "listener" False + "pos" + 0, 0, 0 "use_environment" False "use_orthogonal" False + "x_rot" + 0 + "y_rot" + 0 + + + "distance" + 4 + "listener" + False "pos" 0, 0, 0 + "use_environment" + False + "use_orthogonal" + False + "x_rot" + 0 + "y_rot" + 0 - "viewport_mode" - 1 - "default_light" - True - "ambient_light_color" - 0.15, 0.15, 0.15, 1 - "show_grid" - True - "show_origin" - True + "zfar" + 500 "znear" 0.1 - "default_srgb" - False - "deflight_rot_x" - 0.942478 "__editor_run_settings__" @@ -622,13 +595,9 @@ "run_mode" 0 - "__editor_plugin_screen__" - "Script" 16 - 1, 1, 1, 1 - 0, 0, 0, 0 0.363636 20.7312, 3.21187 83.450417 @@ -640,24 +609,22 @@ 20 9.8 2 - 0, 0, 0, 0.0442478 - 1, 0, 0, 1 - 0, 0, 0, 1 - + ".." + + - - "" + 1, 1 10000000 0.2 31.2428, 4.08784 @@ -680,10 +647,8 @@ "shoot" - "nodes" - -1, -1, 1, 0, -1, 30, 2, 0, 3, 1, 4, 2, 5, 2, 6, 3, 7, 4, 8, 5, 9, 6, 10, 7, 11, 8, 12, 9, 13, 3, 14, 10, 15, 11, 16, 3, 17, 12, 18, 7, 19, 13, 20, 5, 21, 5, 22, 1, 23, 14, 24, 15, 25, 3, 26, 3, 27, 1, 28, 4, 29, 5, 30, 16, 31, 17, 0, 0, 0, 33, 32, -1, 19, 2, 0, 3, 1, 4, 2, 5, 2, 6, 3, 7, 4, 8, 5, 9, 6, 34, 18, 35, 1, 36, 4, 37, 3, 38, 3, 39, 7, 40, 19, 41, 14, 42, 20, 43, 3, 44, 21, 0, 1, 0, 46, 45, -1, 66, 2, 0, 3, 1, 4, 2, 5, 22, 6, 3, 47, 12, 7, 23, 8, 24, 9, 6, 48, 25, 49, 26, 50, 2, 51, 5, 52, 26, 53, 3, 54, 4, 55, 4, 56, 3, 57, 27, 58, 3, 59, 3, 60, 28, 61, 12, 62, 12, 63, 5, 64, 29, 65, 30, 66, 2, 67, 5, 68, 5, 69, 31, 70, 5, 71, 5, 72, 5, 73, 5, 74, 32, 75, 32, 76, 5, 77, 2, 78, 5, 79, 5, 80, 5, 81, 5, 82, 32, 83, 5, 84, 5, 85, 5, 86, 5, 87, 5, 88, 5, 89, 5, 90, 5, 91, 5, 92, 5, 93, 5, 94, 5, 95, 7, 96, 5, 97, 20, 98, 2, 99, 33, 100, 2, 101, 34, 102, 2, 103, 35, 104, 36, 0, 0, 0, 106, 105, -1, 18, 2, 0, 107, 12, 108, 5, 109, 37, 110, 38, 111, 39, 112, 40, 113, 41, 114, 42, 115, 43, 116, 44, 117, 45, 118, 46, 119, 47, 120, 1, 121, 32, 122, 48, 123, 49, 0, 0, 0, 125, 124, -1, 23, 2, 0, 3, 1, 4, 2, 5, 2, 6, 3, 7, 4, 8, 5, 9, 6, 35, 1, 126, 3, 127, 1, 128, 5, 129, 6, 130, 14, 131, 14, 132, 50, 133, 50, 134, 1, 135, 1, 136, 51, 137, 51, 138, 51, 139, 51, 0, 0, 0, 141, 140, -1, 8, 2, 0, 3, 1, 4, 2, 5, 2, 6, 3, 7, 52, 8, 5, 9, 6, 0, 0, 0, 142, 142, -1, 10, 2, 0, 3, 1, 4, 2, 5, 2, 6, 3, 7, 53, 8, 5, 9, 54, 143, 8, 144, 3, 0, 0, 0, 146, 145, -1, 15, 2, 0, 147, 15, 148, 55, 149, 5, 150, 2, 151, 5, 152, 5, 153, 5, 154, 56, 155, 56, 156, 56, 157, 56, 158, 7, 159, 5, 160, 5, 0, 0, 0, 161, 161, -1, 10, 2, 0, 3, 1, 4, 2, 5, 2, 6, 3, 7, 4, 8, 5, 9, 6, 162, 14, 163, 57, 0, 0, 0, 165, 164, -1, 5, 2, 0, 166, 14, 36, 4, 167, 5, 168, 6, 0, 9, 0, 170, 169, -1, 14, 2, 0, 3, 1, 4, 2, 5, 2, 6, 3, 7, 58, 8, 5, 9, 59, 171, 60, 172, 61, 173, 61, 174, 1, 175, 62, 176, 12, 0, 9, 0, 170, 177, -1, 14, 2, 0, 3, 1, 4, 2, 5, 2, 6, 3, 7, 63, 8, 5, 9, 59, 171, 64, 172, 61, 173, 61, 174, 1, 175, 65, 176, 12, 0, 9, 0, 170, 178, -1, 14, 2, 0, 3, 1, 4, 2, 5, 2, 6, 3, 7, 66, 8, 5, 9, 59, 171, 67, 172, 61, 173, 61, 174, 3, 175, 68, 176, 12, 0, 9, 0, 170, 179, -1, 14, 2, 0, 3, 1, 4, 2, 5, 2, 6, 3, 7, 69, 8, 5, 9, 59, 171, 70, 172, 61, 173, 61, 174, 3, 175, 71, 176, 12, 0 - "conns" - + "version" + 1 diff --git a/demos/misc/regex/engine.cfg b/demos/misc/regex/engine.cfg new file mode 100644 index 00000000000..0a6f4f869cf --- /dev/null +++ b/demos/misc/regex/engine.cfg @@ -0,0 +1,4 @@ +[application] + +name="RegEx" +main_scene="res://regex.scn" diff --git a/demos/misc/regex/regex.gd b/demos/misc/regex/regex.gd new file mode 100644 index 00000000000..e648c180931 --- /dev/null +++ b/demos/misc/regex/regex.gd @@ -0,0 +1,22 @@ +extends VBoxContainer + +var regex = RegEx.new() + +func update_expression(): + regex.compile(get_node("Expression").get_text()) + update_text() + +func update_text(): + var text = get_node("Text").get_text() + regex.find(text) + var list = get_node("List") + for child in list.get_children(): + child.queue_free() + for res in regex.get_captures(): + var label = Label.new() + label.set_text(res) + list.add_child(label) + +func _ready(): + get_node("Text").set_text("They asked me \"What's going on \\\"in the manor\\\"?\"") + update_expression() diff --git a/demos/misc/regex/regex.scn b/demos/misc/regex/regex.scn new file mode 100644 index 00000000000..2b62d6b82a6 Binary files /dev/null and b/demos/misc/regex/regex.scn differ diff --git a/drivers/SCsub b/drivers/SCsub index 6ab09736252..3028139f50d 100644 --- a/drivers/SCsub +++ b/drivers/SCsub @@ -29,7 +29,7 @@ if (env["openssl"]=="builtin"): SConscript("rtaudio/SCsub"); SConscript("nedmalloc/SCsub"); -SConscript("trex/SCsub"); +SConscript("nrex/SCsub"); SConscript("chibi/SCsub"); if (env["vorbis"]=="yes" or env["speex"]=="yes" or env["theora"]=="yes"): SConscript("ogg/SCsub"); diff --git a/drivers/nrex/README.md b/drivers/nrex/README.md new file mode 100644 index 00000000000..f150a5d76f9 --- /dev/null +++ b/drivers/nrex/README.md @@ -0,0 +1,64 @@ +# NREX: Node RegEx + +Small node-based regular expression library. It only does text pattern +matchhing, not replacement. To use add the files `nrex.hpp`, `nrex.cpp` +and `nrex_config.h` to your project and follow the example: + + nrex regex; + regex.compile("^(fo+)bar$"); + + nrex_result captures[regex.capture_size()]; + if (regex.match("foobar", captures)) + { + std::cout << captures[0].start << std::endl; + std::cout << captures[0].length << std::endl; + } + +More details about its use is documented in `nrex.hpp` + +Currently supported features: + * Capturing `()` and non-capturing `(?:)` groups + * Any character `.` + * Shorthand caracter classes `\w\W\s\S\d\D` + * User-defined character classes such as `[A-Za-z]` + * Simple quantifiers `?`, `*` and `+` + * Range quantifiers `{0,1}` + * Lazy (non-greedy) quantifiers `*?` + * Begining `^` and end `$` anchors + * Alternation `|` + * Backreferences `\1` to `\99` + +To do list: + * Unicode `\uFFFF` code points + +## License + +Copyright (c) 2015, Zher Huei Lee +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + 3. Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS +IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/drivers/trex/SCsub b/drivers/nrex/SCsub similarity index 88% rename from drivers/trex/SCsub rename to drivers/nrex/SCsub index 877be8e3d90..2441d3061b2 100644 --- a/drivers/trex/SCsub +++ b/drivers/nrex/SCsub @@ -2,8 +2,7 @@ Import('env') sources = [ - - 'trex.c', + 'nrex.cpp', 'regex.cpp', ] env.add_source_files(env.drivers_sources, sources) diff --git a/drivers/nrex/nrex.cpp b/drivers/nrex/nrex.cpp new file mode 100644 index 00000000000..696d46240e7 --- /dev/null +++ b/drivers/nrex/nrex.cpp @@ -0,0 +1,910 @@ +// NREX: Node RegEx +// +// Copyright (c) 2015, Zher Huei Lee +// All rights reserved. +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// + +#include "nrex.hpp" + +#ifdef NREX_UNICODE +#include +#include +#define NREX_ISALPHANUM iswalnum +#define NREX_STRLEN wcslen +#else +#include +#include +#define NREX_ISALPHANUM isalnum +#define NREX_STRLEN strlen +#endif + +#ifdef NREX_THROW_ERROR +#define NREX_COMPILE_ERROR(M) throw nrex_compile_error(M) +#else +#define NREX_COMPILE_ERROR(M) reset(); return false +#endif + +#ifndef NREX_NEW +#define NREX_NEW(X) new X +#define NREX_NEW_ARRAY(X, N) new X[N] +#define NREX_DELETE(X) delete X +#define NREX_DELETE_ARRAY(X) delete[] X +#endif + +template +class nrex_array +{ + private: + T* _data; + unsigned int _reserved; + unsigned int _size; + public: + nrex_array() + : _data(NREX_NEW_ARRAY(T, 2)) + , _reserved(2) + , _size(0) + { + } + + ~nrex_array() + { + NREX_DELETE_ARRAY(_data); + } + + unsigned int size() const + { + return _size; + } + + void reserve(unsigned int size) + { + T* old = _data; + _data = NREX_NEW_ARRAY(T, size); + _reserved = size; + for (unsigned int i = 0; i < _size; ++i) + { + _data[i] = old[i]; + } + NREX_DELETE_ARRAY(old); + } + + void push(T item) + { + if (_size == _reserved) + { + reserve(_reserved * 2); + } + _data[_size] = item; + _size++; + } + + T& top() + { + return _data[_size - 1]; + } + + const T& operator[] (unsigned int i) const + { + return _data[i]; + } + + void pop() + { + if (_size > 0) + { + --_size; + } + } +}; + +static nrex_char nrex_unescape(nrex_char repr) +{ + switch (repr) + { + case '^': return '^'; + case '$': return '$'; + case '(': return '('; + case ')': return ')'; + case '\\': return '\\'; + case '.': return '.'; + case '+': return '+'; + case '*': return '*'; + case '?': return '?'; + case '-': return '-'; + case 'a': return '\a'; + case 'e': return '\e'; + case 'f': return '\f'; + case 'n': return '\n'; + case 'r': return '\r'; + case 't': return '\t'; + case 'v': return '\v'; + } + return 0; +} + +struct nrex_search +{ + public: + const nrex_char* str; + nrex_result* captures; + int end; + bool complete; + + nrex_char at(int pos) + { + return str[pos]; + } + + nrex_search(const nrex_char* str, nrex_result* captures) + : str(str) + , captures(captures) + , end(0) + { + } +}; + +struct nrex_node +{ + nrex_node* next; + nrex_node* previous; + nrex_node* parent; + bool quantifiable; + + nrex_node(bool quantify = false) + : next(NULL) + , previous(NULL) + , parent(NULL) + , quantifiable(quantify) + { + } + + virtual ~nrex_node() + { + if (next) + { + NREX_DELETE(next); + } + } + + virtual int test(nrex_search* s, int pos) const + { + return next ? next->test(s, pos) : -1; + } + + virtual int test_parent(nrex_search* s, int pos) const + { + if (next) + { + pos = next->test(s, pos); + } + if (parent && pos >= 0) + { + pos = parent->test_parent(s, pos); + } + if (pos >= 0) + { + s->complete = true; + } + return pos; + } +}; + +struct nrex_node_group : public nrex_node +{ + int capturing; + bool negate; + nrex_array childset; + nrex_node* back; + + nrex_node_group(int capturing) + : nrex_node(true) + , capturing(capturing) + , negate(false) + , back(NULL) + { + } + + virtual ~nrex_node_group() + { + for (unsigned int i = 0; i < childset.size(); ++i) + { + NREX_DELETE(childset[i]); + } + + } + + int test(nrex_search* s, int pos) const + { + if (capturing >= 0) + { + s->captures[capturing].start = pos; + } + for (unsigned int i = 0; i < childset.size(); ++i) + { + s->complete = false; + int res = childset[i]->test(s, pos); + if (s->complete) + { + return res; + } + if (negate) + { + if (res < 0) + { + res = pos + 1; + } + else + { + return -1; + } + } + if (res >= 0) + { + if (capturing >= 0) + { + s->captures[capturing].length = res - pos; + } + return next ? next->test(s, res) : res; + } + } + return -1; + } + + virtual int test_parent(nrex_search* s, int pos) const + { + if (capturing >= 0) + { + s->captures[capturing].length = pos - s->captures[capturing].start; + } + return nrex_node::test_parent(s, pos); + } + + void add_childset() + { + back = NULL; + } + + void add_child(nrex_node* node) + { + node->parent = this; + node->previous = back; + if (back) + { + back->next = node; + } + else + { + childset.push(node); + } + back = node; + } + + nrex_node* swap_back(nrex_node* node) + { + if (!back) + { + add_child(node); + return NULL; + } + nrex_node* old = back; + if (!old->previous) + { + childset.pop(); + } + back = old->previous; + add_child(node); + return old; + } +}; + +struct nrex_node_char : public nrex_node +{ + nrex_char ch; + + nrex_node_char(nrex_char c) + : nrex_node(true) + , ch(c) + { + } + + int test(nrex_search* s, int pos) const + { + if (s->end == pos || s->at(pos) != ch) + { + return -1; + } + return next ? next->test(s, pos + 1) : pos + 1; + } +}; + +struct nrex_node_range : public nrex_node +{ + nrex_char start; + nrex_char end; + + nrex_node_range(nrex_char s, nrex_char e) + : nrex_node(true) + , start(s) + , end(e) + { + } + + int test(nrex_search* s, int pos) const + { + if (s->end == pos) + { + return -1; + } + nrex_char c = s->at(pos); + if (c < start || end < c) + { + return -1; + } + return next ? next->test(s, pos + 1) : pos + 1; + } +}; + +static bool nrex_is_whitespace(nrex_char repr) +{ + switch (repr) + { + case ' ': + case '\t': + case '\r': + case '\n': + case '\f': + return true; + } + return false; +} + +static bool nrex_is_shorthand(nrex_char repr) +{ + switch (repr) + { + case 'W': + case 'w': + case 'D': + case 'd': + case 'S': + case 's': + return true; + } + return false; +} + +struct nrex_node_shorthand : public nrex_node +{ + nrex_char repr; + + nrex_node_shorthand(nrex_char c) + : nrex_node(true) + , repr(c) + { + } + + int test(nrex_search* s, int pos) const + { + if (s->end == pos) + { + return -1; + } + bool found = false; + bool invert = false; + nrex_char c = s->at(pos); + switch (repr) + { + case '.': + found = true; + break; + case 'W': + invert = true; + case 'w': + if (c == '_' || NREX_ISALPHANUM(c)) + { + found = true; + } + break; + case 'D': + invert = true; + case 'd': + if ('0' <= c && c <= '9') + { + found = true; + } + break; + case 'S': + invert = true; + case 's': + if (nrex_is_whitespace(c)) + { + found = true; + } + break; + } + if (found == invert) + { + return -1; + } + return next ? next->test(s, pos + 1) : pos + 1; + } +}; + +static bool nrex_is_quantifier(nrex_char repr) +{ + switch (repr) + { + case '?': + case '*': + case '+': + case '{': + return true; + } + return false; +} + +struct nrex_node_quantifier : public nrex_node +{ + int min; + int max; + bool greedy; + nrex_node* child; + + nrex_node_quantifier() + : nrex_node() + , min(0) + , max(0) + , greedy(true) + , child(NULL) + { + } + + virtual ~nrex_node_quantifier() + { + if (child) + { + NREX_DELETE(child); + } + } + + int test(nrex_search* s, int pos) const + { + nrex_array backtrack; + backtrack.push(pos); + while (backtrack.top() <= s->end) + { + if (max >= 1 && backtrack.size() > (unsigned int)max) + { + break; + } + if (!greedy && (unsigned int)min < backtrack.size()) + { + int res = backtrack.top(); + if (next) + { + res = next->test(s, res); + } + if (s->complete) + { + return res; + } + if (res >= 0 && parent->test_parent(s, res) >= 0) + { + return res; + } + } + int res = child->test(s, backtrack.top()); + if (s->complete) + { + return res; + } + if (res < 0 || res == backtrack.top()) + { + break; + } + backtrack.push(res); + } + while (greedy && (unsigned int) min < backtrack.size()) + { + int res = backtrack.top(); + if (next) + { + res = next->test(s, res); + } + if (res >= 0 && parent->test_parent(s, res) >= 0) + { + return res; + } + if (s->complete) + { + return res; + } + backtrack.pop(); + } + return -1; + } +}; + +struct nrex_node_anchor : public nrex_node +{ + bool end; + + nrex_node_anchor(bool end) + : nrex_node() + , end(end) + { + } + + int test(nrex_search* s, int pos) const + { + if (!end && pos != 0) + { + return -1; + } + else if (end && pos != s->end) + { + return -1; + } + return next ? next->test(s, pos) : pos; + } +}; + +struct nrex_node_backreference : public nrex_node +{ + int ref; + + nrex_node_backreference(int ref) + : nrex_node(true) + , ref(ref) + { + } + + int test(nrex_search* s, int pos) const + { + nrex_result& r = s->captures[ref]; + for (int i = 0; i < r.length; ++i) + { + if (pos + i >= s->end) + { + return -1; + } + if (s->at(r.start + i) != s->at(pos + i)) + { + return -1; + } + } + return next ? next->test(s, pos + r.length) : pos + r.length; + } +}; + +nrex::nrex() + : _capturing(0) + , _root(NULL) +{ +} + +nrex::~nrex() +{ + if (_root) + { + NREX_DELETE(_root); + } +} + +bool nrex::valid() const +{ + return (_root != NULL); +} + +void nrex::reset() +{ + _capturing = 0; + if (_root) + { + NREX_DELETE(_root); + } + _root = NULL; +} + +int nrex::capture_size() const +{ + return _capturing + 1; +} + +bool nrex::compile(const nrex_char* pattern) +{ + reset(); + nrex_node_group* root = NREX_NEW(nrex_node_group(_capturing)); + nrex_array stack; + stack.push(root); + _root = root; + + for (const nrex_char* c = pattern; c[0] != '\0'; ++c) + { + if (c[0] == '(') + { + if (c[1] == '?') + { + if (c[2] == ':') + { + c = &c[2]; + nrex_node_group* group = NREX_NEW(nrex_node_group(-1)); + stack.top()->add_child(group); + stack.push(group); + } + else + { + NREX_COMPILE_ERROR("unrecognised qualifier for parenthesis"); + } + } + else if (_capturing < 99) + { + nrex_node_group* group = NREX_NEW(nrex_node_group(++_capturing)); + stack.top()->add_child(group); + stack.push(group); + } + else + { + nrex_node_group* group = NREX_NEW(nrex_node_group(-1)); + stack.top()->add_child(group); + stack.push(group); + } + } + else if (c[0] == ')') + { + if (stack.size() > 1) + { + stack.pop(); + } + else + { + NREX_COMPILE_ERROR("unexpected ')'"); + } + } + else if (c[0] == '[') + { + nrex_node_group* group = NREX_NEW(nrex_node_group(-1)); + stack.top()->add_child(group); + if (c[1] == '^') + { + group->negate = true; + ++c; + } + while (true) + { + group->add_childset(); + ++c; + if (c[0] == '\0') + { + NREX_COMPILE_ERROR("unclosed character class '[]'"); + } + if (c[0] == ']') + { + break; + } + else if (c[0] == '\\') + { + nrex_char unescaped = nrex_unescape(c[1]); + if (unescaped) + { + group->add_child(NREX_NEW(nrex_node_char(unescaped))); + ++c; + } + else if (nrex_is_shorthand(c[1])) + { + group->add_child(NREX_NEW(nrex_node_shorthand(c[1]))); + ++c; + } + else + { + NREX_COMPILE_ERROR("escape token not recognised"); + } + } + else + { + if (c[1] == '-' && c[2] != '\0') + { + bool range = false; + if ('A' <= c[0] && c[0] <= 'Z' && 'A' <= c[2] && c[2] <= 'Z') + { + range = true; + } + if ('a' <= c[0] && c[0] <= 'z' && 'a' <= c[2] && c[2] <= 'z') + { + range = true; + } + if ('0' <= c[0] && c[0] <= '9' && '0' <= c[2] && c[2] <= '9') + { + range = true; + } + if (range) + { + group->add_child(NREX_NEW(nrex_node_range(c[0], c[2]))); + c = &c[2]; + continue; + } + } + group->add_child(NREX_NEW(nrex_node_char(c[0]))); + } + + } + } + else if (nrex_is_quantifier(c[0])) + { + nrex_node_quantifier* quant = NREX_NEW(nrex_node_quantifier); + quant->child = stack.top()->swap_back(quant); + if (quant->child == NULL || !quant->child->quantifiable) + { + NREX_COMPILE_ERROR("element not quantifiable"); + } + quant->child->previous = NULL; + quant->child->next = NULL; + quant->child->parent = quant; + if (c[0] == '?') + { + quant->min = 0; + quant->max = 1; + } + else if (c[0] == '+') + { + quant->min = 1; + quant->max = -1; + } + else if (c[0] == '*') + { + quant->min = 0; + quant->max = -1; + } + else if (c[0] == '{') + { + bool max_set = false; + quant->min = 0; + quant->max = -1; + while (true) + { + ++c; + if (c[0] == '\0') + { + NREX_COMPILE_ERROR("unclosed range quantifier '{}'"); + } + else if (c[0] == '}') + { + break; + } + else if (c[0] == ',') + { + max_set = true; + continue; + } + else if (c[0] < '0' || '9' < c[0]) + { + NREX_COMPILE_ERROR("expected numeric digits, ',' or '}'"); + } + if (max_set) + { + if (quant->max < 0) + { + quant->max = int(c[0] - '0'); + } + else + { + quant->max = quant->max * 10 + int(c[0] - '0'); + } + } + else + { + quant->min = quant->min * 10 + int(c[0] - '0'); + } + } + if (!max_set) + { + quant->max = quant->min; + } + } + if (c[1] == '?') + { + quant->greedy = false; + ++c; + } + } + else if (c[0] == '|') + { + stack.top()->add_childset(); + } + else if (c[0] == '^' || c[0] == '$') + { + stack.top()->add_child(NREX_NEW(nrex_node_anchor((c[0] == '$')))); + } + else if (c[0] == '.') + { + stack.top()->add_child(NREX_NEW(nrex_node_shorthand('.'))); + } + else if (c[0] == '\\') + { + nrex_char unescaped = nrex_unescape(c[1]); + if (unescaped) + { + stack.top()->add_child(NREX_NEW(nrex_node_char(unescaped))); + ++c; + } + else if (nrex_is_shorthand(c[1])) + { + stack.top()->add_child(NREX_NEW(nrex_node_shorthand(c[1]))); + ++c; + } + else if ('1' <= c[1] && c[1] <= '9') + { + int ref = 0; + if ('0' <= c[2] && c[2] <= '9') + { + ref = int(c[1] - '0') * 10 + int(c[2] - '0'); + c = &c[2]; + } + else + { + ref = int(c[1] - '0'); + ++c; + } + if (ref > _capturing) + { + NREX_COMPILE_ERROR("backreference to non-existent capture"); + } + stack.top()->add_child(NREX_NEW(nrex_node_backreference(ref))); + } + else + { + NREX_COMPILE_ERROR("escape token not recognised"); + } + } + else + { + stack.top()->add_child(NREX_NEW(nrex_node_char(c[0]))); + } + } + return true; +} + +bool nrex::match(const nrex_char* str, nrex_result* captures, int offset, int end) const +{ + nrex_search s(str, captures); + if (end >= offset) + { + s.end = end; + } + else + { + s.end = NREX_STRLEN(str); + } + for (int i = offset; i < s.end; ++i) + { + for (int c = 0; c <= _capturing; ++c) + { + captures[c].start = 0; + captures[c].length = 0; + } + if (_root->test(&s, i) >= 0) + { + return true; + } + } + return false; +} diff --git a/drivers/nrex/nrex.hpp b/drivers/nrex/nrex.hpp new file mode 100644 index 00000000000..2a6aa08e1d4 --- /dev/null +++ b/drivers/nrex/nrex.hpp @@ -0,0 +1,144 @@ +// NREX: Node RegEx +// +// Copyright (c) 2015, Zher Huei Lee +// All rights reserved. +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// + +#ifndef NREX_HPP +#define NREX_HPP + +#include "nrex_config.h" + +#ifdef NREX_UNICODE +typedef wchar_t nrex_char; +#else +typedef char nrex_char; +#endif + +/*! + * \brief Struct to contain the range of a capture result + * + * The range provided is relative to the begining of the searched string. + * + * \see nrex_node::match() + */ +struct nrex_result +{ + public: + int start; /*!< Start of text range */ + int length; /*!< Length of text range */ +}; + +class nrex_node; + +/*! + * \brief Holds the compiled regex pattern + */ +class nrex +{ + private: + int _capturing; + nrex_node* _root; + public: + nrex(); + ~nrex(); + + /*! + * \brief Removes the compiled regex and frees up the memory + */ + void reset(); + + /*! + * \brief Checks if there is a compiled regex being stored + * \return True if present, False if not present + */ + bool valid() const; + + /*! + * \brief Provides number of captures the compiled regex uses + * + * This is used to provide the array size of the captures needed for + * nrex::match() to work. The size is actually the number of capture + * groups + one for the matching of the entire pattern. The result is + * always capped at 100. + * + * \return The number of captures + */ + int capture_size() const; + + /*! + * \brief Compiles the provided regex pattern + * + * This automatically removes the existing compiled regex if already + * present. + * + * If the NREX_THROW_ERROR was defined it would automatically throw a + * runtime error nrex_compile_error if it encounters a problem when + * parsing the pattern. + * + * \param The regex pattern + * \return True if the pattern was succesfully compiled + */ + bool compile(const nrex_char* pattern); + + /*! + * \brief Uses the pattern to search through the provided string + * \param str The text to search through. It only needs to be + * null terminated if the end point is not provided. + * This also determines the starting anchor. + * \param captures The array of results to store the capture results. + * The size of that array needs to be the same as the + * size given in nrex::capture_size(). As it matches + * the function fills the array with the results. 0 is + * the result for the entire pattern, 1 and above + * corresponds to the regex capture group if present. + * \param offset The starting point of the search. This does not move + * the starting anchor. Defaults to 0. + * \param end The end point of the search. This also determines + * the ending anchor. If a number less than the offset + * is provided, the search would be done until null + * termination. Defaults to -1. + * \return True if a match was found. False otherwise. + */ + bool match(const nrex_char* str, nrex_result* captures, int offset = 0, int end = -1) const; +}; + +#ifdef NREX_THROW_ERROR + +#include + +class nrex_compile_error : std::runtime_error +{ + public: + nrex_compile_error(const char* message) + : std::runtime_error(message) + { + } + + ~nrex_compile_error() throw() + { + } +}; + +#endif + +#endif // NREX_HPP diff --git a/drivers/nrex/nrex_config.h b/drivers/nrex/nrex_config.h new file mode 100644 index 00000000000..540f34f8b49 --- /dev/null +++ b/drivers/nrex/nrex_config.h @@ -0,0 +1,12 @@ +// Godot-specific configuration +// To use this, replace nrex_config.h + +#include "core/os/memory.h" + +#define NREX_UNICODE +//#define NREX_THROW_ERROR + +#define NREX_NEW(X) memnew(X) +#define NREX_NEW_ARRAY(X, N) memnew_arr(X, N) +#define NREX_DELETE(X) memdelete(X) +#define NREX_DELETE_ARRAY(X) memdelete_arr(X) diff --git a/drivers/nrex/regex.cpp b/drivers/nrex/regex.cpp new file mode 100644 index 00000000000..0a813c34907 --- /dev/null +++ b/drivers/nrex/regex.cpp @@ -0,0 +1,114 @@ +/*************************************************/ +/* regex.cpp */ +/*************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/*************************************************/ +/* Source code within this file is: */ +/* (c) 2007-2010 Juan Linietsky, Ariel Manzur */ +/* All Rights Reserved. */ +/*************************************************/ + +#include "regex.h" +#include "nrex.hpp" +#include "core/os/memory.h" + +void RegEx::_bind_methods() { + + ObjectTypeDB::bind_method(_MD("compile","pattern"),&RegEx::compile); + ObjectTypeDB::bind_method(_MD("find","text","start","end"),&RegEx::find, DEFVAL(0), DEFVAL(-1)); + ObjectTypeDB::bind_method(_MD("clear"),&RegEx::clear); + ObjectTypeDB::bind_method(_MD("is_valid"),&RegEx::is_valid); + ObjectTypeDB::bind_method(_MD("get_capture_count"),&RegEx::get_capture_count); + ObjectTypeDB::bind_method(_MD("get_capture","capture"),&RegEx::get_capture); + ObjectTypeDB::bind_method(_MD("get_captures"),&RegEx::_bind_get_captures); + +}; + +StringArray RegEx::_bind_get_captures() const { + + StringArray ret; + int count = get_capture_count(); + for (int i=0; i captures; + nrex exp; protected: static void _bind_methods(); - - int _bind_find(const String& p_text, int p_start = 0, int p_end = -1) const; StringArray _bind_get_captures() const; + public: void clear(); - - Error compile(const String& p_pattern); bool is_valid() const; - bool match(const String& p_text, List* p_captures = NULL, int p_start = 0, int p_end = -1) const; - bool find(const String& p_text, int& p_rstart, int &p_rend, List* p_captures = NULL, int p_start = 0, int p_end = -1) const; int get_capture_count() const; - Error get_capture_limits(int p_capture, int& p_start, int& p_len) const; - String get_capture(int p_idx) const; + String get_capture(int capture) const; + Error compile(const String& p_pattern); + int find(const String& p_text, int p_start = 0, int p_end = -1) const; RegEx(); RegEx(const String& p_pattern); diff --git a/drivers/register_driver_types.cpp b/drivers/register_driver_types.cpp index e730171fbba..01f6a8b5b00 100644 --- a/drivers/register_driver_types.cpp +++ b/drivers/register_driver_types.cpp @@ -48,7 +48,7 @@ #endif -#include "drivers/trex/regex.h" +#include "drivers/nrex/regex.h" #ifdef MUSEPACK_ENABLED #include "mpc/audio_stream_mpc.h" diff --git a/drivers/trex/TRexpp.h b/drivers/trex/TRexpp.h deleted file mode 100644 index 8391e47414e..00000000000 --- a/drivers/trex/TRexpp.h +++ /dev/null @@ -1,75 +0,0 @@ -#ifndef _TREXPP_H_ -#define _TREXPP_H_ -/*************************************************************** - T-Rex a tiny regular expression library - - Copyright (C) 2003-2004 Alberto Demichelis - - This software is provided 'as-is', without any express - or implied warranty. In no event will the authors be held - liable for any damages arising from the use of this software. - - Permission is granted to anyone to use this software for - any purpose, including commercial applications, and to alter - it and redistribute it freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; - you must not claim that you wrote the original software. - If you use this software in a product, an acknowledgment - in the product documentation would be appreciated but - is not required. - - 2. Altered source versions must be plainly marked as such, - and must not be misrepresented as being the original software. - - 3. This notice may not be removed or altered from any - source distribution. - -****************************************************************/ - -extern "C" { -#include "trex.h" -} - -struct TRexParseException{TRexParseException(const TRexChar *c):desc(c){}const TRexChar *desc;}; - -class TRexpp { -public: - TRexpp() { _exp = (TRex *)0; } - ~TRexpp() { CleanUp(); } - // compiles a regular expression - void Compile(const TRexChar *pattern) { - const TRexChar *error; - CleanUp(); - if(!(_exp = trex_compile(pattern,&error))) - throw TRexParseException(error); - } - // return true if the given text match the expression - bool Match(const TRexChar* text) { - return _exp?(trex_match(_exp,text) != 0):false; - } - // Searches for the first match of the expression in a zero terminated string - bool Search(const TRexChar* text, const TRexChar** out_begin, const TRexChar** out_end) { - return _exp?(trex_search(_exp,text,out_begin,out_end) != 0):false; - } - // Searches for the first match of the expression in a string sarting at text_begin and ending at text_end - bool SearchRange(const TRexChar* text_begin,const TRexChar* text_end,const TRexChar** out_begin, const TRexChar** out_end) { - return _exp?(trex_searchrange(_exp,text_begin,text_end,out_begin,out_end) != 0):false; - } - bool GetSubExp(int n, const TRexChar** out_begin, int *out_len) - { - TRexMatch match; - TRexBool res = _exp?(trex_getsubexp(_exp,n,&match)):TRex_False; - if(res) { - *out_begin = match.begin; - *out_len = match.len; - return true; - } - return false; - } - int GetSubExpCount() { return _exp?trex_getsubexpcount(_exp):0; } -private: - void CleanUp() { if(_exp) trex_free(_exp); _exp = (TRex *)0; } - TRex *_exp; -}; -#endif //_TREXPP_H_ \ No newline at end of file diff --git a/drivers/trex/history.txt b/drivers/trex/history.txt deleted file mode 100644 index 5cfe8770b4a..00000000000 --- a/drivers/trex/history.txt +++ /dev/null @@ -1,15 +0,0 @@ -===version 1.3 --fixed a bug for GCC users(thx Brendan) - -===version 1.2 --added word boundary match \b and \B --added vertical tab escape \v --\w now also matches '_' (underscore) --fixed greediness for * and + - -===version 1.1 , April 1, 2004 --fixed some minor bug --added predefined character classes(\w,\W,\s,\S etc...) - -===version 1.0 , February 23, 2004 --first public realase \ No newline at end of file diff --git a/drivers/trex/readme.txt b/drivers/trex/readme.txt deleted file mode 100644 index 1d93558e921..00000000000 --- a/drivers/trex/readme.txt +++ /dev/null @@ -1,171 +0,0 @@ -T-REX 1.3 http://tiny-rex.sourceforge.net ----------------------------------------------------------------------- - T-Rex a tiny regular expression library - - Copyright (C) 2003-2006 Alberto Demichelis - - This software is provided 'as-is', without any express - or implied warranty. In no event will the authors be held - liable for any damages arising from the use of this software. - - Permission is granted to anyone to use this software for - any purpose, including commercial applications, and to alter - it and redistribute it freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; - you must not claim that you wrote the original software. - If you use this software in a product, an acknowledgment - in the product documentation would be appreciated but - is not required. - - 2. Altered source versions must be plainly marked as such, - and must not be misrepresented as being the original software. - - 3. This notice may not be removed or altered from any - source distribution. - ----------------------------------------------------------------------- -TRex implements the following expressions - -\ Quote the next metacharacter -^ Match the beginning of the string -. Match any character -$ Match the end of the string -| Alternation -() Grouping (creates a capture) -[] Character class - -==GREEDY CLOSURES== -* Match 0 or more times -+ Match 1 or more times -? Match 1 or 0 times -{n} Match exactly n times -{n,} Match at least n times -{n,m} Match at least n but not more than m times - -==ESCAPE CHARACTERS== -\t tab (HT, TAB) -\n newline (LF, NL) -\r return (CR) -\f form feed (FF) - -==PREDEFINED CLASSES== -\l lowercase next char -\u uppercase next char -\a letters -\A non letters -\w alphanimeric [0-9a-zA-Z] -\W non alphanimeric -\s space -\S non space -\d digits -\D non nondigits -\x exadecimal digits -\X non exadecimal digits -\c control charactrs -\C non control charactrs -\p punctation -\P non punctation -\b word boundary -\B non word boundary - ----------------------------------------------------------------------- -API DOC ----------------------------------------------------------------------- -TRex *trex_compile(const TRexChar *pattern,const TRexChar **error); - -compiles an expression and returns a pointer to the compiled version. -in case of failure returns NULL.The returned object has to be deleted -through the function trex_free(). - -pattern - a pointer to a zero terminated string containing the pattern that - has to be compiled. -error - apointer to a string pointer that will be set with an error string - in case of failure. - ----------------------------------------------------------------------- -void trex_free(TRex *exp) - -deletes a expression structure created with trex_compile() - -exp - the expression structure that has to be deleted - ----------------------------------------------------------------------- -TRexBool trex_match(TRex* exp,const TRexChar* text) - -returns TRex_True if the string specified in the parameter text is an -exact match of the expression, otherwise returns TRex_False. - -exp - the compiled expression -text - the string that has to be tested - ----------------------------------------------------------------------- -TRexBool trex_search(TRex* exp,const TRexChar* text, const TRexChar** out_begin, const TRexChar** out_end) - -searches the first match of the expressin in the string specified in the parameter text. -if the match is found returns TRex_True and the sets out_begin to the beginning of the -match and out_end at the end of the match; otherwise returns TRex_False. - -exp - the compiled expression -text - the string that has to be tested -out_begin - a pointer to a string pointer that will be set with the beginning of the match -out_end - a pointer to a string pointer that will be set with the end of the match - ----------------------------------------------------------------------- -TREX_API TRexBool trex_searchrange(TRex* exp,const TRexChar* text_begin,const TRexChar* text_end,const TRexChar** out_begin, const TRexChar** out_end) - -searches the first match of the expressin in the string delimited -by the parameter text_begin and text_end. -if the match is found returns TRex_True and the sets out_begin to the beginning of the -match and out_end at the end of the match; otherwise returns TRex_False. - -exp - the compiled expression -text_begin - a pointer to the beginnning of the string that has to be tested -text_end - a pointer to the end of the string that has to be tested -out_begin - a pointer to a string pointer that will be set with the beginning of the match -out_end - a pointer to a string pointer that will be set with the end of the match - ----------------------------------------------------------------------- -int trex_getsubexpcount(TRex* exp) - -returns the number of sub expressions matched by the expression - -exp - the compiled expression - ---------------------------------------------------------------------- -TRexBool trex_getsubexp(TRex* exp, int n, TRexMatch *submatch) - -retrieve the begin and and pointer to the length of the sub expression indexed -by n. The result is passed trhough the struct TRexMatch: - -typedef struct { - const TRexChar *begin; - int len; -} TRexMatch; - -the function returns TRex_True if n is valid index otherwise TRex_False. - -exp - the compiled expression -n - the index of the submatch -submatch - a pointer to structure that will store the result - -this function works also after a match operation has been performend. - diff --git a/drivers/trex/regex.cpp b/drivers/trex/regex.cpp deleted file mode 100644 index 11cd6256e29..00000000000 --- a/drivers/trex/regex.cpp +++ /dev/null @@ -1,163 +0,0 @@ -/*************************************************/ -/* regex.cpp */ -/*************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/*************************************************/ -/* Source code within this file is: */ -/* (c) 2007-2010 Juan Linietsky, Ariel Manzur */ -/* All Rights Reserved. */ -/*************************************************/ - -#include "regex.h" - -extern "C" { - -#define _UNICODE -#include "trex.h" - -}; - -void RegEx::_bind_methods() { - - ObjectTypeDB::bind_method(_MD("compile","pattern"),&RegEx::compile); - ObjectTypeDB::bind_method(_MD("find","text", "start","end"),&RegEx::_bind_find, DEFVAL(0), DEFVAL(-1)); - ObjectTypeDB::bind_method(_MD("get_captures"),&RegEx::_bind_get_captures); -}; - -Error RegEx::compile(const String& p_pattern) { - - clear(); - const TRexChar* error; - exp = trex_compile(p_pattern.c_str(), &error); - ERR_FAIL_COND_V(!exp, FAILED); - return OK; -}; - - -int RegEx::_bind_find(const String& p_text, int p_start, int p_end) const { - - int start, end; - bool ret = find(p_text, start, end, NULL, p_start, p_end); - - return ret?start:-1; -}; - -bool RegEx::find(const String& p_text, int& p_rstart, int &p_rend, List* p_captures, int p_start, int p_end) const { - - ERR_FAIL_COND_V( !exp, false ); - text=p_text; - - const CharType* str = p_text.c_str(); - const CharType* start = str + p_start; - const CharType* end = str + (p_end == -1?p_text.size():p_end); - - const CharType* out_begin; - const CharType* out_end; - - bool ret = trex_searchrange(exp, start, end, &out_begin, &out_end); - if (ret) { - - p_rstart = out_begin - str; - p_rend = out_end - str; - - if (p_captures) { - - int count = get_capture_count(); - for (int i=0; ipush_back(p_text.substr(start, len)); - }; - }; - } else { - - p_rstart = -1; - }; - - return ret; -}; - - -bool RegEx::match(const String& p_text, List* p_captures, int p_start, int p_end) const { - - ERR_FAIL_COND_V( !exp, false ); - - int start, end; - return find(p_text, start, end, p_captures, p_start, p_end); -}; - -int RegEx::get_capture_count() const { - - ERR_FAIL_COND_V( exp == NULL, -1 ); - - return trex_getsubexpcount(exp); -}; - -Error RegEx::get_capture_limits(int p_capture, int& p_start, int& p_len) const { - - ERR_FAIL_COND_V( exp == NULL, ERR_UNCONFIGURED ); - - TRexMatch match; - TRexBool res = trex_getsubexp(exp, p_capture, &match); - ERR_FAIL_COND_V( !res, FAILED ); - p_start = (int)(match.begin - text.c_str()); - p_len = match.len; - - return OK; -}; - -String RegEx::get_capture(int p_idx) const { - - ERR_FAIL_COND_V( exp == NULL, "" ); - int start, len; - Error ret = get_capture_limits(p_idx, start, len); - ERR_FAIL_COND_V(ret != OK, ""); - if (len == 0) - return ""; - return text.substr(start, len); -}; - -StringArray RegEx::_bind_get_captures() const { - - StringArray ret; - int count = get_capture_count(); - for (int i=0; i -#include - -#ifdef _UNICODE -#define trex_sprintf swprintf -#else -#define trex_sprintf sprintf -#endif - -int main(int argc, char* argv[]) -{ - const TRexChar *begin,*end; - TRexChar sTemp[200]; - const TRexChar *error = NULL; - TRex *x = trex_compile(_TREXC("(x{1,5})xx"),&error); - if(x) { - trex_sprintf(sTemp,_TREXC("xxxxxxx")); - if(trex_search(x,sTemp,&begin,&end)) - { - int i,n = trex_getsubexpcount(x); - TRexMatch match; - for(i = 0; i < n; i++) - { - TRexChar t[200]; - trex_getsubexp(x,i,&match); - trex_sprintf(t,_TREXC("[%%d]%%.%ds\n"),match.len); - trex_printf(t,i,match.begin); - } - trex_printf(_TREXC("match! %d sub matches\n"),trex_getsubexpcount(x)); - } - else { - trex_printf(_TREXC("no match!\n")); - } - trex_free(x); - } - else { - trex_printf(_TREXC("compilation error [%s]!\n"),error?error:_TREXC("undefined")); - } - return 0; -} diff --git a/drivers/trex/trex.c b/drivers/trex/trex.c deleted file mode 100644 index b3668c3a117..00000000000 --- a/drivers/trex/trex.c +++ /dev/null @@ -1,643 +0,0 @@ - /* see copyright notice in trex.h */ -#include -#include -#include -#include -#include "trex.h" - -#ifdef _UINCODE -#define scisprint iswprint -#define scstrlen wcslen -#define scprintf wprintf -#define _SC(x) L##c -#else -#define scisprint isprint -#define scstrlen strlen -#define scprintf printf -#define _SC(x) (x) -#endif - -#ifdef _DEBUG -#include - -static const TRexChar *g_nnames[] = -{ - _SC("NONE"),_SC("OP_GREEDY"), _SC("OP_OR"), - _SC("OP_EXPR"),_SC("OP_NOCAPEXPR"),_SC("OP_DOT"), _SC("OP_CLASS"), - _SC("OP_CCLASS"),_SC("OP_NCLASS"),_SC("OP_RANGE"),_SC("OP_CHAR"), - _SC("OP_EOL"),_SC("OP_BOL"),_SC("OP_WB") -}; - -#endif -#define OP_GREEDY (MAX_CHAR+1) // * + ? {n} -#define OP_OR (MAX_CHAR+2) -#define OP_EXPR (MAX_CHAR+3) //parentesis () -#define OP_NOCAPEXPR (MAX_CHAR+4) //parentesis (?:) -#define OP_DOT (MAX_CHAR+5) -#define OP_CLASS (MAX_CHAR+6) -#define OP_CCLASS (MAX_CHAR+7) -#define OP_NCLASS (MAX_CHAR+8) //negates class the [^ -#define OP_RANGE (MAX_CHAR+9) -#define OP_CHAR (MAX_CHAR+10) -#define OP_EOL (MAX_CHAR+11) -#define OP_BOL (MAX_CHAR+12) -#define OP_WB (MAX_CHAR+13) - -#define TREX_SYMBOL_ANY_CHAR ('.') -#define TREX_SYMBOL_GREEDY_ONE_OR_MORE ('+') -#define TREX_SYMBOL_GREEDY_ZERO_OR_MORE ('*') -#define TREX_SYMBOL_GREEDY_ZERO_OR_ONE ('?') -#define TREX_SYMBOL_BRANCH ('|') -#define TREX_SYMBOL_END_OF_STRING ('$') -#define TREX_SYMBOL_BEGINNING_OF_STRING ('^') -#define TREX_SYMBOL_ESCAPE_CHAR ('\\') - - -typedef int TRexNodeType; - -typedef struct tagTRexNode{ - TRexNodeType type; - int left; - int right; - int next; -}TRexNode; - -struct TRex{ - const TRexChar *_eol; - const TRexChar *_bol; - const TRexChar *_p; - int _first; - int _op; - TRexNode *_nodes; - int _nallocated; - int _nsize; - int _nsubexpr; - TRexMatch *_matches; - int _currsubexp; - void *_jmpbuf; - const TRexChar **_error; -}; - -static int trex_list(TRex *exp); - -static int trex_newnode(TRex *exp, TRexNodeType type) -{ - TRexNode n; - int newid; - n.type = type; - n.next = n.right = n.left = -1; - if(type == OP_EXPR) - n.right = exp->_nsubexpr++; - if(exp->_nallocated < (exp->_nsize + 1)) { - //int oldsize = exp->_nallocated; - exp->_nallocated *= 2; - exp->_nodes = (TRexNode *)realloc(exp->_nodes, exp->_nallocated * sizeof(TRexNode)); - } - exp->_nodes[exp->_nsize++] = n; - newid = exp->_nsize - 1; - return (int)newid; -} - -static void trex_error(TRex *exp,const TRexChar *error) -{ - if(exp->_error) *exp->_error = error; - longjmp(*((jmp_buf*)exp->_jmpbuf),-1); -} - -static void trex_expect(TRex *exp, int n){ - if((*exp->_p) != n) - trex_error(exp, _SC("expected paren")); - exp->_p++; -} - -static TRexChar trex_escapechar(TRex *exp) -{ - if(*exp->_p == TREX_SYMBOL_ESCAPE_CHAR){ - exp->_p++; - switch(*exp->_p) { - case 'v': exp->_p++; return '\v'; - case 'n': exp->_p++; return '\n'; - case 't': exp->_p++; return '\t'; - case 'r': exp->_p++; return '\r'; - case 'f': exp->_p++; return '\f'; - default: return (*exp->_p++); - } - } else if(!scisprint(*exp->_p)) trex_error(exp,_SC("letter expected")); - return (*exp->_p++); -} - -static int trex_charclass(TRex *exp,int classid) -{ - int n = trex_newnode(exp,OP_CCLASS); - exp->_nodes[n].left = classid; - return n; -} - -static int trex_charnode(TRex *exp,TRexBool isclass) -{ - TRexChar t; - if(*exp->_p == TREX_SYMBOL_ESCAPE_CHAR) { - exp->_p++; - switch(*exp->_p) { - case 'n': exp->_p++; return trex_newnode(exp,'\n'); - case 't': exp->_p++; return trex_newnode(exp,'\t'); - case 'r': exp->_p++; return trex_newnode(exp,'\r'); - case 'f': exp->_p++; return trex_newnode(exp,'\f'); - case 'v': exp->_p++; return trex_newnode(exp,'\v'); - case 'a': case 'A': case 'w': case 'W': case 's': case 'S': - case 'd': case 'D': case 'x': case 'X': case 'c': case 'C': - case 'p': case 'P': case 'l': case 'u': - { - t = *exp->_p; exp->_p++; - return trex_charclass(exp,t); - } - case 'b': - case 'B': - if(!isclass) { - int node = trex_newnode(exp,OP_WB); - exp->_nodes[node].left = *exp->_p; - exp->_p++; - return node; - } //else default - default: - t = *exp->_p; exp->_p++; - return trex_newnode(exp,t); - } - } - else if(!scisprint(*exp->_p)) { - - trex_error(exp,_SC("letter expected")); - } - t = *exp->_p; exp->_p++; - return trex_newnode(exp,t); -} -static int trex_class(TRex *exp) -{ - int ret = -1; - int first = -1,chain; - if(*exp->_p == TREX_SYMBOL_BEGINNING_OF_STRING){ - ret = trex_newnode(exp,OP_NCLASS); - exp->_p++; - }else ret = trex_newnode(exp,OP_CLASS); - - if(*exp->_p == ']') trex_error(exp,_SC("empty class")); - chain = ret; - while(*exp->_p != ']' && exp->_p != exp->_eol) { - if(*exp->_p == '-' && first != -1){ - int r,t; - if(*exp->_p++ == ']') trex_error(exp,_SC("unfinished range")); - r = trex_newnode(exp,OP_RANGE); - if(first>*exp->_p) trex_error(exp,_SC("invalid range")); - if(exp->_nodes[first].type == OP_CCLASS) trex_error(exp,_SC("cannot use character classes in ranges")); - exp->_nodes[r].left = exp->_nodes[first].type; - t = trex_escapechar(exp); - exp->_nodes[r].right = t; - exp->_nodes[chain].next = r; - chain = r; - first = -1; - } - else{ - if(first!=-1){ - int c = first; - exp->_nodes[chain].next = c; - chain = c; - first = trex_charnode(exp,TRex_True); - } - else{ - first = trex_charnode(exp,TRex_True); - } - } - } - if(first!=-1){ - int c = first; - exp->_nodes[chain].next = c; - chain = c; - first = -1; - } - /* hack? */ - exp->_nodes[ret].left = exp->_nodes[ret].next; - exp->_nodes[ret].next = -1; - return ret; -} - -static int trex_parsenumber(TRex *exp) -{ - int ret = *exp->_p-'0'; - int positions = 10; - exp->_p++; - while(isdigit(*exp->_p)) { - ret = ret*10+(*exp->_p++-'0'); - if(positions==1000000000) trex_error(exp,_SC("overflow in numeric constant")); - positions *= 10; - }; - return ret; -} - -static int trex_element(TRex *exp) -{ - int ret = -1; - switch(*exp->_p) - { - case '(': { - int expr,newn; - exp->_p++; - - - if(*exp->_p =='?') { - exp->_p++; - trex_expect(exp,':'); - expr = trex_newnode(exp,OP_NOCAPEXPR); - } - else - expr = trex_newnode(exp,OP_EXPR); - newn = trex_list(exp); - exp->_nodes[expr].left = newn; - ret = expr; - trex_expect(exp,')'); - } - break; - case '[': - exp->_p++; - ret = trex_class(exp); - trex_expect(exp,']'); - break; - case TREX_SYMBOL_END_OF_STRING: exp->_p++; ret = trex_newnode(exp,OP_EOL);break; - case TREX_SYMBOL_ANY_CHAR: exp->_p++; ret = trex_newnode(exp,OP_DOT);break; - default: - ret = trex_charnode(exp,TRex_False); - break; - } - - { - int op; - TRexBool isgreedy = TRex_False; - unsigned short p0 = 0, p1 = 0; - switch(*exp->_p){ - case TREX_SYMBOL_GREEDY_ZERO_OR_MORE: p0 = 0; p1 = 0xFFFF; exp->_p++; isgreedy = TRex_True; break; - case TREX_SYMBOL_GREEDY_ONE_OR_MORE: p0 = 1; p1 = 0xFFFF; exp->_p++; isgreedy = TRex_True; break; - case TREX_SYMBOL_GREEDY_ZERO_OR_ONE: p0 = 0; p1 = 1; exp->_p++; isgreedy = TRex_True; break; - case '{': - exp->_p++; - if(!isdigit(*exp->_p)) trex_error(exp,_SC("number expected")); - p0 = (unsigned short)trex_parsenumber(exp); - /*******************************/ - switch(*exp->_p) { - case '}': - p1 = p0; exp->_p++; - break; - case ',': - exp->_p++; - p1 = 0xFFFF; - if(isdigit(*exp->_p)){ - p1 = (unsigned short)trex_parsenumber(exp); - } - trex_expect(exp,'}'); - break; - default: - trex_error(exp,_SC(", or } expected")); - } - /*******************************/ - isgreedy = TRex_True; - break; - - } - if(isgreedy) { - int nnode = trex_newnode(exp,OP_GREEDY); - op = OP_GREEDY; - exp->_nodes[nnode].left = ret; - exp->_nodes[nnode].right = ((p0)<<16)|p1; - ret = nnode; - } - } - if((*exp->_p != TREX_SYMBOL_BRANCH) && (*exp->_p != ')') && (*exp->_p != TREX_SYMBOL_GREEDY_ZERO_OR_MORE) && (*exp->_p != TREX_SYMBOL_GREEDY_ONE_OR_MORE) && (*exp->_p != '\0')) { - int nnode = trex_element(exp); - exp->_nodes[ret].next = nnode; - } - - return ret; -} - -static int trex_list(TRex *exp) -{ - int ret=-1,e; - if(*exp->_p == TREX_SYMBOL_BEGINNING_OF_STRING) { - exp->_p++; - ret = trex_newnode(exp,OP_BOL); - } - e = trex_element(exp); - if(ret != -1) { - exp->_nodes[ret].next = e; - } - else ret = e; - - if(*exp->_p == TREX_SYMBOL_BRANCH) { - int temp,tright; - exp->_p++; - temp = trex_newnode(exp,OP_OR); - exp->_nodes[temp].left = ret; - tright = trex_list(exp); - exp->_nodes[temp].right = tright; - ret = temp; - } - return ret; -} - -static TRexBool trex_matchcclass(int cclass,TRexChar c) -{ - switch(cclass) { - case 'a': return isalpha(c)?TRex_True:TRex_False; - case 'A': return !isalpha(c)?TRex_True:TRex_False; - case 'w': return (isalnum(c) || c == '_')?TRex_True:TRex_False; - case 'W': return (!isalnum(c) && c != '_')?TRex_True:TRex_False; - case 's': return isspace(c)?TRex_True:TRex_False; - case 'S': return !isspace(c)?TRex_True:TRex_False; - case 'd': return isdigit(c)?TRex_True:TRex_False; - case 'D': return !isdigit(c)?TRex_True:TRex_False; - case 'x': return isxdigit(c)?TRex_True:TRex_False; - case 'X': return !isxdigit(c)?TRex_True:TRex_False; - case 'c': return iscntrl(c)?TRex_True:TRex_False; - case 'C': return !iscntrl(c)?TRex_True:TRex_False; - case 'p': return ispunct(c)?TRex_True:TRex_False; - case 'P': return !ispunct(c)?TRex_True:TRex_False; - case 'l': return islower(c)?TRex_True:TRex_False; - case 'u': return isupper(c)?TRex_True:TRex_False; - } - return TRex_False; /*cannot happen*/ -} - -static TRexBool trex_matchclass(TRex* exp,TRexNode *node,TRexChar c) -{ - do { - switch(node->type) { - case OP_RANGE: - if(c >= node->left && c <= node->right) return TRex_True; - break; - case OP_CCLASS: - if(trex_matchcclass(node->left,c)) return TRex_True; - break; - default: - if(c == node->type)return TRex_True; - } - } while((node->next != -1) && (node = &exp->_nodes[node->next])); - return TRex_False; -} - -static const TRexChar *trex_matchnode(TRex* exp,TRexNode *node,const TRexChar *str,TRexNode *next) -{ - - TRexNodeType type = node->type; - switch(type) { - case OP_GREEDY: { - //TRexNode *greedystop = (node->next != -1) ? &exp->_nodes[node->next] : NULL; - TRexNode *greedystop = NULL; - int p0 = (node->right >> 16)&0x0000FFFF, p1 = node->right&0x0000FFFF, nmaches = 0; - const TRexChar *s=str, *good = str; - - if(node->next != -1) { - greedystop = &exp->_nodes[node->next]; - } - else { - greedystop = next; - } - - while((nmaches == 0xFFFF || nmaches < p1)) { - - const TRexChar *stop; - if(!(s = trex_matchnode(exp,&exp->_nodes[node->left],s,greedystop))) - break; - nmaches++; - good=s; - if(greedystop) { - //checks that 0 matches satisfy the expression(if so skips) - //if not would always stop(for instance if is a '?') - if(greedystop->type != OP_GREEDY || - (greedystop->type == OP_GREEDY && ((greedystop->right >> 16)&0x0000FFFF) != 0)) - { - TRexNode *gnext = NULL; - if(greedystop->next != -1) { - gnext = &exp->_nodes[greedystop->next]; - }else if(next && next->next != -1){ - gnext = &exp->_nodes[next->next]; - } - stop = trex_matchnode(exp,greedystop,s,gnext); - if(stop) { - //if satisfied stop it - if(p0 == p1 && p0 == nmaches) break; - else if(nmaches >= p0 && p1 == 0xFFFF) break; - else if(nmaches >= p0 && nmaches <= p1) break; - } - } - } - - if(s >= exp->_eol) - break; - } - if(p0 == p1 && p0 == nmaches) return good; - else if(nmaches >= p0 && p1 == 0xFFFF) return good; - else if(nmaches >= p0 && nmaches <= p1) return good; - return NULL; - } - case OP_OR: { - const TRexChar *asd = str; - TRexNode *temp=&exp->_nodes[node->left]; - while( (asd = trex_matchnode(exp,temp,asd,NULL)) ) { - if(temp->next != -1) - temp = &exp->_nodes[temp->next]; - else - return asd; - } - asd = str; - temp = &exp->_nodes[node->right]; - while( (asd = trex_matchnode(exp,temp,asd,NULL)) ) { - if(temp->next != -1) - temp = &exp->_nodes[temp->next]; - else - return asd; - } - return NULL; - break; - } - case OP_EXPR: - case OP_NOCAPEXPR:{ - TRexNode *n = &exp->_nodes[node->left]; - const TRexChar *cur = str; - int capture = -1; - if(node->type != OP_NOCAPEXPR && node->right == exp->_currsubexp) { - capture = exp->_currsubexp; - exp->_matches[capture].begin = cur; - exp->_currsubexp++; - } - - do { - TRexNode *subnext = NULL; - if(n->next != -1) { - subnext = &exp->_nodes[n->next]; - }else { - subnext = next; - } - if(!(cur = trex_matchnode(exp,n,cur,subnext))) { - if(capture != -1){ - exp->_matches[capture].begin = 0; - exp->_matches[capture].len = 0; - } - return NULL; - } - } while((n->next != -1) && (n = &exp->_nodes[n->next])); - - if(capture != -1) - exp->_matches[capture].len = cur - exp->_matches[capture].begin; - return cur; - } - case OP_WB: - if((str == exp->_bol && !isspace(*str)) - || (str == exp->_eol && !isspace(*(str-1))) - || (!isspace(*str) && isspace(*(str+1))) - || (isspace(*str) && !isspace(*(str+1))) ) { - return (node->left == 'b')?str:NULL; - } - return (node->left == 'b')?NULL:str; - case OP_BOL: - if(str == exp->_bol) return str; - return NULL; - case OP_EOL: - if(str == exp->_eol) return str; - return NULL; - case OP_DOT:{ - *str++; - } - return str; - case OP_NCLASS: - case OP_CLASS: - if(trex_matchclass(exp,&exp->_nodes[node->left],*str)?(type == OP_CLASS?TRex_True:TRex_False):(type == OP_NCLASS?TRex_True:TRex_False)) { - *str++; - return str; - } - return NULL; - case OP_CCLASS: - if(trex_matchcclass(node->left,*str)) { - *str++; - return str; - } - return NULL; - default: /* char */ - if(*str != node->type) return NULL; - *str++; - return str; - } - return NULL; -} - -/* public api */ -TRex *trex_compile(const TRexChar *pattern,const TRexChar **error) -{ - TRex *exp = (TRex *)malloc(sizeof(TRex)); - exp->_eol = exp->_bol = NULL; - exp->_p = pattern; - exp->_nallocated = (int)scstrlen(pattern) * sizeof(TRexChar); - exp->_nodes = (TRexNode *)malloc(exp->_nallocated * sizeof(TRexNode)); - exp->_nsize = 0; - exp->_matches = 0; - exp->_nsubexpr = 0; - exp->_first = trex_newnode(exp,OP_EXPR); - exp->_error = error; - exp->_jmpbuf = malloc(sizeof(jmp_buf)); - if(setjmp(*((jmp_buf*)exp->_jmpbuf)) == 0) { - int res = trex_list(exp); - exp->_nodes[exp->_first].left = res; - if(*exp->_p!='\0') - trex_error(exp,_SC("unexpected character")); -#ifdef _DEBUG - { - int nsize,i; - TRexNode *t; - nsize = exp->_nsize; - t = &exp->_nodes[0]; - scprintf(_SC("\n")); - for(i = 0;i < nsize; i++) { - if(exp->_nodes[i].type>MAX_CHAR) - scprintf(_SC("[%02d] %10s "),i,g_nnames[exp->_nodes[i].type-MAX_CHAR]); - else - scprintf(_SC("[%02d] %10c "),i,exp->_nodes[i].type); - scprintf(_SC("left %02d right %02d next %02d\n"),exp->_nodes[i].left,exp->_nodes[i].right,exp->_nodes[i].next); - } - scprintf(_SC("\n")); - } -#endif - exp->_matches = (TRexMatch *) malloc(exp->_nsubexpr * sizeof(TRexMatch)); - memset(exp->_matches,0,exp->_nsubexpr * sizeof(TRexMatch)); - } - else{ - trex_free(exp); - return NULL; - } - return exp; -} - -void trex_free(TRex *exp) -{ - if(exp) { - if(exp->_nodes) free(exp->_nodes); - if(exp->_jmpbuf) free(exp->_jmpbuf); - if(exp->_matches) free(exp->_matches); - free(exp); - } -} - -TRexBool trex_match(TRex* exp,const TRexChar* text) -{ - const TRexChar* res = NULL; - exp->_bol = text; - exp->_eol = text + scstrlen(text); - exp->_currsubexp = 0; - res = trex_matchnode(exp,exp->_nodes,text,NULL); - if(res == NULL || res != exp->_eol) - return TRex_False; - return TRex_True; -} - -TRexBool trex_searchrange(TRex* exp,const TRexChar* text_begin,const TRexChar* text_end,const TRexChar** out_begin, const TRexChar** out_end) -{ - const TRexChar *cur = NULL; - int node = exp->_first; - if(text_begin >= text_end) return TRex_False; - exp->_bol = text_begin; - exp->_eol = text_end; - do { - cur = text_begin; - while(node != -1) { - exp->_currsubexp = 0; - cur = trex_matchnode(exp,&exp->_nodes[node],cur,NULL); - if(!cur) - break; - node = exp->_nodes[node].next; - } - *text_begin++; - } while(cur == NULL && text_begin != text_end); - - if(cur == NULL) - return TRex_False; - - --text_begin; - - if(out_begin) *out_begin = text_begin; - if(out_end) *out_end = cur; - return TRex_True; -} - -TRexBool trex_search(TRex* exp,const TRexChar* text, const TRexChar** out_begin, const TRexChar** out_end) -{ - return trex_searchrange(exp,text,text + scstrlen(text),out_begin,out_end); -} - -int trex_getsubexpcount(TRex* exp) -{ - return exp->_nsubexpr; -} - -TRexBool trex_getsubexp(TRex* exp, int n, TRexMatch *subexp) -{ - if( n<0 || n >= exp->_nsubexpr) return TRex_False; - *subexp = exp->_matches[n]; - return TRex_True; -} - diff --git a/drivers/trex/trex.h b/drivers/trex/trex.h deleted file mode 100644 index 46e2e73fd50..00000000000 --- a/drivers/trex/trex.h +++ /dev/null @@ -1,70 +0,0 @@ -#ifndef _TREX_H_ -#define _TREX_H_ -/*************************************************************** - T-Rex a tiny regular expression library - - Copyright (C) 2003-2006 Alberto Demichelis - - This software is provided 'as-is', without any express - or implied warranty. In no event will the authors be held - liable for any damages arising from the use of this software. - - Permission is granted to anyone to use this software for - any purpose, including commercial applications, and to alter - it and redistribute it freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; - you must not claim that you wrote the original software. - If you use this software in a product, an acknowledgment - in the product documentation would be appreciated but - is not required. - - 2. Altered source versions must be plainly marked as such, - and must not be misrepresented as being the original software. - - 3. This notice may not be removed or altered from any - source distribution. - -****************************************************************/ - -#define _UNICODE - - -#ifdef _UNICODE -#define TRexChar wchar_t -#define MAX_CHAR 0xFFFF -#define _TREXC(c) L##c -#define trex_strlen wcslen -#define trex_printf wprintf -#else -#define TRexChar char -#define MAX_CHAR 0xFF -#define _TREXC(c) (c) -#define trex_strlen strlen -#define trex_printf printf -#endif - -#ifndef TREX_API -#define TREX_API extern -#endif - -#define TRex_True 1 -#define TRex_False 0 - -typedef unsigned int TRexBool; -typedef struct TRex TRex; - -typedef struct { - const TRexChar *begin; - int len; -} TRexMatch; - -TREX_API TRex *trex_compile(const TRexChar *pattern,const TRexChar **error); -TREX_API void trex_free(TRex *exp); -TREX_API TRexBool trex_match(TRex* exp,const TRexChar* text); -TREX_API TRexBool trex_search(TRex* exp,const TRexChar* text, const TRexChar** out_begin, const TRexChar** out_end); -TREX_API TRexBool trex_searchrange(TRex* exp,const TRexChar* text_begin,const TRexChar* text_end,const TRexChar** out_begin, const TRexChar** out_end); -TREX_API int trex_getsubexpcount(TRex* exp); -TREX_API TRexBool trex_getsubexp(TRex* exp, int n, TRexMatch *subexp); - -#endif diff --git a/platform/x11/os_x11.cpp b/platform/x11/os_x11.cpp index f8c570a5c04..b34d1ba7c8c 100644 --- a/platform/x11/os_x11.cpp +++ b/platform/x11/os_x11.cpp @@ -267,6 +267,7 @@ void OS_X11::initialize(const VideoMode& p_desired,int p_video_driver,int p_audi for(int i=0;iset_singleton(); if (AudioDriverManagerSW::get_driver(i)->init()==OK) { success=true; print_line("Audio Driver Failed: "+String(AudioDriverManagerSW::get_driver(p_audio_driver)->get_name())); diff --git a/scene/2d/tile_map.cpp b/scene/2d/tile_map.cpp index 2fca1e67e86..17f93f816ff 100644 --- a/scene/2d/tile_map.cpp +++ b/scene/2d/tile_map.cpp @@ -579,6 +579,10 @@ void TileMap::_make_quadrant_dirty(Map::Element *Q) { call_deferred("_update_dirty_quadrants"); } +void TileMap::set_cellv(const Vector2& p_pos,int p_tile,bool p_flip_x,bool p_flip_y,bool p_transpose) { + + set_cell(p_pos.x,p_pos.y,p_tile,p_flip_x,p_flip_y,p_transpose); +} void TileMap::set_cell(int p_x,int p_y,int p_tile,bool p_flip_x,bool p_flip_y,bool p_transpose) { @@ -1106,6 +1110,7 @@ void TileMap::_bind_methods() { ObjectTypeDB::bind_method(_MD("get_collision_bounce"),&TileMap::get_collision_bounce); ObjectTypeDB::bind_method(_MD("set_cell","x","y","tile","flip_x","flip_y","transpose"),&TileMap::set_cell,DEFVAL(false),DEFVAL(false),DEFVAL(false)); + ObjectTypeDB::bind_method(_MD("set_cellv","pos","tile","flip_x","flip_y","transpose"),&TileMap::set_cellv,DEFVAL(false),DEFVAL(false),DEFVAL(false)); ObjectTypeDB::bind_method(_MD("get_cell","x","y"),&TileMap::get_cell); ObjectTypeDB::bind_method(_MD("is_cell_x_flipped","x","y"),&TileMap::is_cell_x_flipped); ObjectTypeDB::bind_method(_MD("is_cell_y_flipped","x","y"),&TileMap::is_cell_y_flipped); diff --git a/scene/2d/tile_map.h b/scene/2d/tile_map.h index 84ca65da4f6..60534cce151 100644 --- a/scene/2d/tile_map.h +++ b/scene/2d/tile_map.h @@ -207,6 +207,8 @@ public: bool is_cell_y_flipped(int p_x,int p_y) const; bool is_cell_transposed(int p_x,int p_y) const; + void set_cellv(const Vector2& p_pos,int p_tile,bool p_flip_x=false,bool p_flip_y=false,bool p_transpose=false); + Rect2 get_item_rect() const; void set_collision_layer(uint32_t p_layer); diff --git a/scene/gui/tabs.cpp b/scene/gui/tabs.cpp index 40a6e20c374..a849d3ae728 100644 --- a/scene/gui/tabs.cpp +++ b/scene/gui/tabs.cpp @@ -56,7 +56,14 @@ Size2 Tabs::get_minimum_size() const { else ms.width+=tab_bg->get_minimum_size().width; + if (tabs[i].right_button.is_valid()) { + Ref rb=tabs[i].right_button; + Size2 bms = rb->get_size()+get_stylebox("button")->get_minimum_size(); + bms.width+=get_constant("hseparation"); + ms.width+=bms.width; + ms.height=MAX(bms.height+tab_bg->get_minimum_size().height,ms.height); + } } return ms; @@ -66,6 +73,39 @@ Size2 Tabs::get_minimum_size() const { void Tabs::_input_event(const InputEvent& p_event) { + if (p_event.type==InputEvent::MOUSE_MOTION) { + + Point2 pos( p_event.mouse_motion.x, p_event.mouse_motion.y ); + + int hover=-1; + for(int i=0;i=tabs[i].ofs_cache && pos.x icon; if (tabs[i].icon.is_valid()) { - Ref icon = tabs[i].icon; + icon = tabs[i].icon; if (icon.is_valid()) { lsize+=icon->get_width(); if (s!="") @@ -151,6 +200,16 @@ void Tabs::_notification(int p_what) { } } + if (tabs[i].right_button.is_valid()) { + Ref style = get_stylebox("button"); + Ref rb=tabs[i].right_button; + + lsize+=get_constant("hseparation"); + lsize+=style->get_margin(MARGIN_LEFT); + lsize+=rb->get_width(); + lsize+=style->get_margin(MARGIN_RIGHT); + + } Ref sb; int va; @@ -184,7 +243,37 @@ void Tabs::_notification(int p_what) { font->draw(ci, Point2i( w, sb->get_margin(MARGIN_TOP)+((sb_rect.size.y-sb_ms.y)-font->get_height())/2+font->get_ascent() ), s, col ); - w+=slen+sb->get_margin(MARGIN_RIGHT); + w+=slen; + + if (tabs[i].right_button.is_valid()) { + Ref style = get_stylebox("button"); + Ref rb=tabs[i].right_button; + + w+=get_constant("hseparation"); + + Rect2 rb_rect; + rb_rect.size=style->get_minimum_size()+rb->get_size(); + rb_rect.pos.x=w; + rb_rect.pos.y=sb->get_margin(MARGIN_TOP)+((sb_rect.size.y-sb_ms.y)-(rb_rect.size.y))/2; + + if (rb_hover==i) { + if (rb_pressing) + get_stylebox("button_pressed")->draw(ci,rb_rect); + else + style->draw(ci,rb_rect); + } + + w+=style->get_margin(MARGIN_LEFT); + + rb->draw(ci,Point2i( w,rb_rect.pos.y+style->get_margin(MARGIN_TOP) )); + w+=rb->get_width(); + w+=style->get_margin(MARGIN_RIGHT); + tabs[i].rb_rect=rb_rect; + + + } + + w+=sb->get_margin(MARGIN_RIGHT); tabs[i].size_cache=w-tabs[i].ofs_cache; @@ -252,6 +341,23 @@ Ref Tabs::get_tab_icon(int p_tab) const{ } + + +void Tabs::set_tab_right_button(int p_tab,const Ref& p_right_button){ + + ERR_FAIL_INDEX(p_tab,tabs.size()); + tabs[p_tab].right_button=p_right_button; + update(); + minimum_size_changed(); + +} +Ref Tabs::get_tab_right_button(int p_tab) const{ + + ERR_FAIL_INDEX_V(p_tab,tabs.size(),Ref()); + return tabs[p_tab].right_button; + +} + void Tabs::add_tab(const String& p_str,const Ref& p_icon) { Tab t; @@ -316,6 +422,7 @@ void Tabs::_bind_methods() { ObjectTypeDB::bind_method(_MD("get_tab_align"),&Tabs::get_tab_align); ADD_SIGNAL(MethodInfo("tab_changed",PropertyInfo(Variant::INT,"tab"))); + ADD_SIGNAL(MethodInfo("right_button_pressed",PropertyInfo(Variant::INT,"tab"))); ADD_PROPERTY( PropertyInfo(Variant::INT, "current_tab", PROPERTY_HINT_RANGE,"-1,4096,1",PROPERTY_USAGE_EDITOR), _SCS("set_current_tab"), _SCS("get_current_tab") ); @@ -328,5 +435,7 @@ Tabs::Tabs() { current=0; tab_align=ALIGN_CENTER; + rb_hover=-1; + rb_pressing=false; } diff --git a/scene/gui/tabs.h b/scene/gui/tabs.h index 8d4d0123f89..5cb0d9e9166 100644 --- a/scene/gui/tabs.h +++ b/scene/gui/tabs.h @@ -51,6 +51,8 @@ private: Ref icon; int ofs_cache; int size_cache; + Ref right_button; + Rect2 rb_rect; }; Vector tabs; @@ -58,6 +60,8 @@ private: Control *_get_tab(int idx) const; int _get_top_margin() const; TabAlign tab_align; + int rb_hover; + bool rb_pressing; protected: @@ -75,6 +79,9 @@ public: void set_tab_icon(int p_tab,const Ref& p_icon); Ref get_tab_icon(int p_tab) const; + void set_tab_right_button(int p_tab,const Ref& p_right_button); + Ref get_tab_right_button(int p_tab) const; + void set_tab_align(TabAlign p_align); TabAlign get_tab_align() const; diff --git a/scene/main/node.cpp b/scene/main/node.cpp index 7e31bf8dd07..8336ce35f60 100644 --- a/scene/main/node.cpp +++ b/scene/main/node.cpp @@ -196,6 +196,14 @@ void Node::_propagate_enter_tree() { } data.blocked--; + +#ifdef DEBUG_ENABLED + + if (ScriptDebugger::get_singleton() && data.filename!=String()) { + //used for live edit + data.tree->live_scene_edit_cache[data.filename].insert(this); + } +#endif // enter groups } @@ -205,6 +213,28 @@ void Node::_propagate_exit_tree() { //block while removing children +#ifdef DEBUG_ENABLED + + if (ScriptDebugger::get_singleton() && data.filename!=String()) { + //used for live edit + Map >::Element *E=data.tree->live_scene_edit_cache.find(data.filename); + if (E) { + E->get().erase(this); + if (E->get().size()==0) { + data.tree->live_scene_edit_cache.erase(E); + } + } + + Map >::Element *F=data.tree->live_edit_remove_list.find(this); + if (F) { + for (Map::Element*G=F->get().front();G;G=G->next()) { + + memdelete(G->get()); + } + data.tree->live_edit_remove_list.erase(F); + } + } +#endif data.blocked++; for (int i=data.children.size()-1;i>=0;i--) { @@ -552,6 +582,52 @@ void Node::set_human_readable_collision_renaming(bool p_enabled) { } + +String Node::validate_child_name(const String& p_name) const { + + //this approach to autoset node names is human readable but very slow + //it's turned on while running in the editor + + String basename = p_name; + + if (basename==String()) { + + return String(); + } + + int val=1; + + for(;;) { + + String attempted = val > 1 ? (basename + " " +itos(val) ) : basename; + + bool found=false; + + for (int i=0;iget_name() == attempted) { + found=true; + break; + } + + } + + if (found) { + + val++; + continue; + } + + return attempted; + break; + } + + return basename; + +} + void Node::_validate_child_name(Node *p_child) { /* Make sure the name is unique */ @@ -1323,18 +1399,31 @@ int Node::get_position_in_parent() const { -Node *Node::duplicate() const { +Node *Node::duplicate(bool p_use_instancing) const { Node *node=NULL; - Object *obj = ObjectTypeDB::instance(get_type()); - ERR_FAIL_COND_V(!obj,NULL); - node = obj->cast_to(); - if (!node) - memdelete(obj); - ERR_FAIL_COND_V(!node,NULL); + bool instanced=false; + if (p_use_instancing && get_filename()!=String()) { + + Ref res = ResourceLoader::load(get_filename()); + ERR_FAIL_COND_V(res.is_null(),NULL); + node=res->instance(); + ERR_FAIL_COND_V(!node,NULL); + + instanced=true; + + } else { + + Object *obj = ObjectTypeDB::instance(get_type()); + ERR_FAIL_COND_V(!obj,NULL); + node = obj->cast_to(); + if (!node) + memdelete(obj); + ERR_FAIL_COND_V(!node,NULL); + } if (get_filename()!="") { //an instance @@ -1360,7 +1449,10 @@ Node *Node::duplicate() const { if (get_child(i)->data.parent_owned) continue; - Node *dup = get_child(i)->duplicate(); + if (instanced && get_child(i)->data.owner==this) + continue; //part of instance + + Node *dup = get_child(i)->duplicate(p_use_instancing); if (!dup) { memdelete(node); @@ -1882,7 +1974,7 @@ void Node::_bind_methods() { ObjectTypeDB::bind_method(_MD("get_tree:SceneTree"),&Node::get_tree); - ObjectTypeDB::bind_method(_MD("duplicate:Node"),&Node::duplicate); + ObjectTypeDB::bind_method(_MD("duplicate:Node","use_instancing"),&Node::duplicate,DEFVAL(false)); ObjectTypeDB::bind_method(_MD("replace_by","node:Node","keep_data"),&Node::replace_by,DEFVAL(false)); ObjectTypeDB::bind_method(_MD("get_viewport"),&Node::get_viewport); diff --git a/scene/main/node.h b/scene/main/node.h index be91c6e1bbd..a6d5bfbd9fd 100644 --- a/scene/main/node.h +++ b/scene/main/node.h @@ -255,8 +255,9 @@ public: int get_position_in_parent() const; - Node *duplicate() const; + Node *duplicate(bool p_use_instancing=false) const; Node *duplicate_and_reown(const Map& p_reown_map) const; + //Node *clone_tree() const; // used by editors, to save what has changed only @@ -275,6 +276,8 @@ public: static void print_stray_nodes(); + String validate_child_name(const String& p_name) const; + void queue_delete(); //shitty hacks for speed diff --git a/scene/main/scene_main_loop.cpp b/scene/main/scene_main_loop.cpp index 1664a9bea12..45e3d92ece1 100644 --- a/scene/main/scene_main_loop.cpp +++ b/scene/main/scene_main_loop.cpp @@ -1044,7 +1044,371 @@ void SceneTree::add_current_scene(Node * p_current) { current_scene=p_current; root->add_child(p_current); } +#ifdef DEBUG_ENABLED +void SceneTree::_live_edit_node_path_func(const NodePath &p_path,int p_id) { + + live_edit_node_path_cache[p_id]=p_path; +} + +void SceneTree::_live_edit_res_path_func(const String &p_path,int p_id) { + + live_edit_resource_cache[p_id]=p_path; +} + +void SceneTree::_live_edit_node_set_func(int p_id,const StringName& p_prop,const Variant& p_value) { + + if (!live_edit_node_path_cache.has(p_id)) + return; + + NodePath np = live_edit_node_path_cache[p_id]; + Node *base = NULL; + if (root->has_node(live_edit_root)) + base = root->get_node(live_edit_root); + + Map >::Element *E=live_scene_edit_cache.find(live_edit_scene); + if (!E) + return; //scene not editable + + for(Set::Element *F=E->get().front();F;F=F->next()) { + + Node *n=F->get(); + + if (base && !base->is_a_parent_of(n)) + continue; + + if (!n->has_node(np)) + continue; + Node *n2 = n->get_node(np); + + n2->set(p_prop,p_value); + } + +} + +void SceneTree::_live_edit_node_set_res_func(int p_id,const StringName& p_prop,const String& p_value) { + + RES r = ResourceLoader::load(p_value); + if (!r.is_valid()) + return; + _live_edit_node_set_func(p_id,p_prop,r); + +} +void SceneTree::_live_edit_node_call_func(int p_id,const StringName& p_method,VARIANT_ARG_DECLARE) { + + if (!live_edit_node_path_cache.has(p_id)) + return; + + NodePath np = live_edit_node_path_cache[p_id]; + Node *base = NULL; + if (root->has_node(live_edit_root)) + base = root->get_node(live_edit_root); + + Map >::Element *E=live_scene_edit_cache.find(live_edit_scene); + if (!E) + return; //scene not editable + + for(Set::Element *F=E->get().front();F;F=F->next()) { + + Node *n=F->get(); + + if (base && !base->is_a_parent_of(n)) + continue; + + if (!n->has_node(np)) + continue; + Node *n2 = n->get_node(np); + + n2->call(p_method,VARIANT_ARG_PASS); + } +} +void SceneTree::_live_edit_res_set_func(int p_id,const StringName& p_prop,const Variant& p_value) { + + if (!live_edit_resource_cache.has(p_id)) + return; + + String resp = live_edit_resource_cache[p_id]; + + if (!ResourceCache::has(resp)) + return; + + RES r = ResourceCache::get(resp); + if (!r.is_valid()) + return; + + r->set(p_prop,p_value); +} +void SceneTree::_live_edit_res_set_res_func(int p_id,const StringName& p_prop,const String& p_value) { + + RES r = ResourceLoader::load(p_value); + if (!r.is_valid()) + return; + _live_edit_res_set_func(p_id,p_prop,r); + +} +void SceneTree::_live_edit_res_call_func(int p_id,const StringName& p_method,VARIANT_ARG_DECLARE) { + + if (!live_edit_resource_cache.has(p_id)) + return; + + String resp = live_edit_resource_cache[p_id]; + + if (!ResourceCache::has(resp)) + return; + + RES r = ResourceCache::get(resp); + if (!r.is_valid()) + return; + + r->call(p_method,VARIANT_ARG_PASS); +} + +void SceneTree::_live_edit_root_func(const NodePath& p_scene_path,const String& p_scene_from) { + + live_edit_root=p_scene_path; + live_edit_scene=p_scene_from; +} + +void SceneTree::_live_edit_create_node_func(const NodePath& p_parent,const String& p_type,const String& p_name) { + + + Node *base = NULL; + if (root->has_node(live_edit_root)) + base = root->get_node(live_edit_root); + + Map >::Element *E=live_scene_edit_cache.find(live_edit_scene); + if (!E) + return; //scene not editable + + for(Set::Element *F=E->get().front();F;F=F->next()) { + + Node *n=F->get(); + + if (base && !base->is_a_parent_of(n)) + continue; + + if (!n->has_node(p_parent)) + continue; + Node *n2 = n->get_node(p_parent); + + Object *o = ObjectTypeDB::instance(p_type); + if (!o) + continue; + Node *no=o->cast_to(); + no->set_name(p_name); + + n2->add_child(no); + } +} +void SceneTree::_live_edit_instance_node_func(const NodePath& p_parent,const String& p_path,const String& p_name){ + + Ref ps = ResourceLoader::load(p_path); + + if (!ps.is_valid()) + return; + + Node *base = NULL; + if (root->has_node(live_edit_root)) + base = root->get_node(live_edit_root); + + Map >::Element *E=live_scene_edit_cache.find(live_edit_scene); + if (!E) + return; //scene not editable + + for(Set::Element *F=E->get().front();F;F=F->next()) { + + Node *n=F->get(); + + if (base && !base->is_a_parent_of(n)) + continue; + + if (!n->has_node(p_parent)) + continue; + Node *n2 = n->get_node(p_parent); + + + + Node *no=ps->instance(); + no->set_name(p_name); + + n2->add_child(no); + } +} +void SceneTree::_live_edit_remove_node_func(const NodePath& p_at){ + + Node *base = NULL; + if (root->has_node(live_edit_root)) + base = root->get_node(live_edit_root); + + Map >::Element *E=live_scene_edit_cache.find(live_edit_scene); + if (!E) + return; //scene not editable + + for(Set::Element *F=E->get().front();F;) { + + Set::Element *N=F->next(); + + Node *n=F->get(); + + if (base && !base->is_a_parent_of(n)) + continue; + + if (!n->has_node(p_at)) + continue; + Node *n2 = n->get_node(p_at); + + memdelete(n2); + + F=N; + + } +} +void SceneTree::_live_edit_remove_and_keep_node_func(const NodePath& p_at,ObjectID p_keep_id){ + + Node *base = NULL; + if (root->has_node(live_edit_root)) + base = root->get_node(live_edit_root); + + Map >::Element *E=live_scene_edit_cache.find(live_edit_scene); + if (!E) + return; //scene not editable + + + for(Set::Element *F=E->get().front();F;) { + + Set::Element *N=F->next(); + + Node *n=F->get(); + + if (base && !base->is_a_parent_of(n)) + continue; + + if (!n->has_node(p_at)) + continue; + + Node *n2 = n->get_node(p_at); + + n2->get_parent()->remove_child(n2); + + live_edit_remove_list[n][p_keep_id]=n2; + + F=N; + + } +} +void SceneTree::_live_edit_restore_node_func(ObjectID p_id,const NodePath& p_at,int p_at_pos){ + + + Node *base = NULL; + if (root->has_node(live_edit_root)) + base = root->get_node(live_edit_root); + + Map >::Element *E=live_scene_edit_cache.find(live_edit_scene); + if (!E) + return; //scene not editable + + for(Set::Element *F=E->get().front();F;) { + + Set::Element *N=F->next(); + + Node *n=F->get(); + + if (base && !base->is_a_parent_of(n)) + continue; + + if (!n->has_node(p_at)) + continue; + Node *n2 = n->get_node(p_at); + + Map >::Element *EN=live_edit_remove_list.find(n); + + if (!EN) + continue; + + Map::Element *FN=EN->get().find(p_id); + + if (!FN) + continue; + n2->add_child(FN->get()); + + EN->get().erase(FN); + + if (EN->get().size()==0) { + live_edit_remove_list.erase(EN); + } + + F=N; + + } +} +void SceneTree::_live_edit_duplicate_node_func(const NodePath& p_at,const String& p_new_name){ + + Node *base = NULL; + if (root->has_node(live_edit_root)) + base = root->get_node(live_edit_root); + + Map >::Element *E=live_scene_edit_cache.find(live_edit_scene); + if (!E) + return; //scene not editable + + for(Set::Element *F=E->get().front();F;F=F->next()) { + + Node *n=F->get(); + + if (base && !base->is_a_parent_of(n)) + continue; + + if (!n->has_node(p_at)) + continue; + Node *n2 = n->get_node(p_at); + + Node *dup = n2->duplicate(true); + + if (!dup) + continue; + + dup->set_name(p_new_name); + n2->get_parent()->add_child(dup); + + } +} +void SceneTree::_live_edit_reparent_node_func(const NodePath& p_at,const NodePath& p_new_place,const String& p_new_name,int p_at_pos){ + + Node *base = NULL; + if (root->has_node(live_edit_root)) + base = root->get_node(live_edit_root); + + Map >::Element *E=live_scene_edit_cache.find(live_edit_scene); + if (!E) + return; //scene not editable + + for(Set::Element *F=E->get().front();F;F=F->next()) { + + Node *n=F->get(); + + if (base && !base->is_a_parent_of(n)) + continue; + + if (!n->has_node(p_at)) + continue; + Node *nfrom = n->get_node(p_at); + + if (!n->has_node(p_new_place)) + continue; + Node *nto = n->get_node(p_new_place); + + nfrom->get_parent()->remove_child(nfrom); + nfrom->set_name(p_new_name); + + nto->add_child(nfrom); + if (p_at_pos>=0) + nto->move_child(nfrom,p_at_pos); + + } +} + + +#endif void SceneTree::_bind_methods() { @@ -1169,6 +1533,35 @@ SceneTree::SceneTree() { edited_scene_root=NULL; #endif +#ifdef DEBUG_ENABLED + + + live_edit_funcs.udata=this; + live_edit_funcs.node_path_func=_live_edit_node_path_funcs; + live_edit_funcs.res_path_func=_live_edit_res_path_funcs; + live_edit_funcs.node_set_func=_live_edit_node_set_funcs; + live_edit_funcs.node_set_res_func=_live_edit_node_set_res_funcs; + live_edit_funcs.node_call_func=_live_edit_node_call_funcs; + live_edit_funcs.res_set_func=_live_edit_res_set_funcs; + live_edit_funcs.res_set_res_func=_live_edit_res_set_res_funcs; + live_edit_funcs.res_call_func=_live_edit_res_call_funcs; + live_edit_funcs.root_func=_live_edit_root_funcs; + + live_edit_funcs.tree_create_node_func=_live_edit_create_node_funcs; + live_edit_funcs.tree_instance_node_func=_live_edit_instance_node_funcs; + live_edit_funcs.tree_remove_node_func=_live_edit_remove_node_funcs; + live_edit_funcs.tree_remove_and_keep_node_func=_live_edit_remove_and_keep_node_funcs; + live_edit_funcs.tree_restore_node_func=_live_edit_restore_node_funcs; + live_edit_funcs.tree_duplicate_node_func=_live_edit_duplicate_node_funcs; + live_edit_funcs.tree_reparent_node_func=_live_edit_reparent_node_funcs; + + if (ScriptDebugger::get_singleton()) { + ScriptDebugger::get_singleton()->set_live_edit_funcs(&live_edit_funcs); + } + + live_edit_root=NodePath("/root"); + +#endif } diff --git a/scene/main/scene_main_loop.h b/scene/main/scene_main_loop.h index e49c150fbf6..1f09d9c546c 100644 --- a/scene/main/scene_main_loop.h +++ b/scene/main/scene_main_loop.h @@ -164,6 +164,58 @@ friend class Viewport; SelfList::List xform_change_list; +#ifdef DEBUG_ENABLED + + Map live_edit_node_path_cache; + Map live_edit_resource_cache; + + NodePath live_edit_root; + String live_edit_scene; + + Map > live_scene_edit_cache; + Map > live_edit_remove_list; + + ScriptDebugger::LiveEditFuncs live_edit_funcs; + + void _live_edit_node_path_func(const NodePath &p_path,int p_id) ; + void _live_edit_res_path_func(const String &p_path,int p_id) ; + + void _live_edit_node_set_func(int p_id,const StringName& p_prop,const Variant& p_value) ; + void _live_edit_node_set_res_func(int p_id,const StringName& p_prop,const String& p_value) ; + void _live_edit_node_call_func(int p_id,const StringName& p_method,VARIANT_ARG_DECLARE) ; + void _live_edit_res_set_func(int p_id,const StringName& p_prop,const Variant& p_value) ; + void _live_edit_res_set_res_func(int p_id,const StringName& p_prop,const String& p_value) ; + void _live_edit_res_call_func(int p_id,const StringName& p_method,VARIANT_ARG_DECLARE) ; + void _live_edit_root_func(const NodePath& p_scene_path,const String& p_scene_from) ; + + void _live_edit_create_node_func(const NodePath& p_parent,const String& p_type,const String& p_name); + void _live_edit_instance_node_func(const NodePath& p_parent,const String& p_path,const String& p_name); + void _live_edit_remove_node_func(const NodePath& p_at); + void _live_edit_remove_and_keep_node_func(const NodePath& p_at,ObjectID p_keep_id); + void _live_edit_restore_node_func(ObjectID p_id,const NodePath& p_at,int p_at_pos); + void _live_edit_duplicate_node_func(const NodePath& p_at,const String& p_new_name); + void _live_edit_reparent_node_func(const NodePath& p_at,const NodePath& p_new_place,const String& p_new_name,int p_at_pos); + + static void _live_edit_node_path_funcs(void *self,const NodePath &p_path,int p_id) { reinterpret_cast(self)->_live_edit_node_path_func(p_path,p_id); } + static void _live_edit_res_path_funcs(void *self,const String &p_path,int p_id) { reinterpret_cast(self)->_live_edit_res_path_func(p_path,p_id); } + + static void _live_edit_node_set_funcs(void *self,int p_id,const StringName& p_prop,const Variant& p_value) { reinterpret_cast(self)->_live_edit_node_set_func(p_id,p_prop,p_value); } + static void _live_edit_node_set_res_funcs(void *self,int p_id,const StringName& p_prop,const String& p_value) { reinterpret_cast(self)->_live_edit_node_set_res_func(p_id,p_prop,p_value); } + static void _live_edit_node_call_funcs(void *self,int p_id,const StringName& p_method,VARIANT_ARG_DECLARE) { reinterpret_cast(self)->_live_edit_node_call_func(p_id,p_method,VARIANT_ARG_PASS); } + static void _live_edit_res_set_funcs(void *self,int p_id,const StringName& p_prop,const Variant& p_value) { reinterpret_cast(self)->_live_edit_res_set_func(p_id,p_prop,p_value); } + static void _live_edit_res_set_res_funcs(void *self,int p_id,const StringName& p_prop,const String& p_value) { reinterpret_cast(self)->_live_edit_res_set_res_func(p_id,p_prop,p_value); } + static void _live_edit_res_call_funcs(void *self,int p_id,const StringName& p_method,VARIANT_ARG_DECLARE) { reinterpret_cast(self)->_live_edit_res_call_func(p_id,p_method,VARIANT_ARG_PASS); } + static void _live_edit_root_funcs(void *self, const NodePath& p_scene_path,const String& p_scene_from) { reinterpret_cast(self)->_live_edit_root_func(p_scene_path,p_scene_from); } + + static void _live_edit_create_node_funcs(void* self,const NodePath& p_parent,const String& p_type,const String& p_name) { reinterpret_cast(self)->_live_edit_create_node_func(p_parent,p_type,p_name); } + static void _live_edit_instance_node_funcs(void* self,const NodePath& p_parent,const String& p_path,const String& p_name) { reinterpret_cast(self)->_live_edit_instance_node_func(p_parent,p_path,p_name); } + static void _live_edit_remove_node_funcs(void* self,const NodePath& p_at) { reinterpret_cast(self)->_live_edit_remove_node_func(p_at); } + static void _live_edit_remove_and_keep_node_funcs(void* self,const NodePath& p_at,ObjectID p_keep_id) { reinterpret_cast(self)->_live_edit_remove_and_keep_node_func(p_at,p_keep_id); } + static void _live_edit_restore_node_funcs(void* self,ObjectID p_id,const NodePath& p_at,int p_at_pos) { reinterpret_cast(self)->_live_edit_restore_node_func(p_id,p_at,p_at_pos); } + static void _live_edit_duplicate_node_funcs(void* self,const NodePath& p_at,const String& p_new_name) { reinterpret_cast(self)->_live_edit_duplicate_node_func(p_at,p_new_name); } + static void _live_edit_reparent_node_funcs(void* self,const NodePath& p_at,const NodePath& p_new_place,const String& p_new_name,int p_at_pos) { reinterpret_cast(self)->_live_edit_reparent_node_func(p_at,p_new_place,p_new_name,p_at_pos); } + +#endif protected: void _notification(int p_notification); diff --git a/scene/resources/default_theme/default_theme.cpp b/scene/resources/default_theme/default_theme.cpp index 58ba5fba254..819d0a5cb94 100644 --- a/scene/resources/default_theme/default_theme.cpp +++ b/scene/resources/default_theme/default_theme.cpp @@ -250,7 +250,6 @@ void make_default_theme() { t->set_stylebox("hover","ToolButton", make_stylebox( button_normal_png,4,4,4,4) ); t->set_stylebox("disabled","ToolButton", make_empty_stylebox(4,4,4,4) ); t->set_stylebox("focus","ToolButton", focus ); - t->set_font("font","ToolButton", default_font ); t->set_color("font_color","ToolButton", control_font_color ); @@ -678,6 +677,9 @@ void make_default_theme() { t->set_stylebox("tab_fg","Tabs", make_stylebox( tab_current_png,4,4,4,4,16,4,16,4) ); t->set_stylebox("tab_bg","Tabs", make_stylebox( tab_behind_png,4,4,4,4,16,6,16,4) ); t->set_stylebox("panel","Tabs", make_stylebox( tab_container_bg_png,4,4,4,4) ); + t->set_stylebox("button_pressed","Tabs", make_stylebox( button_pressed_png,4,4,4,4) ); + t->set_stylebox("button","Tabs", make_stylebox( button_normal_png,4,4,4,4) ); + t->set_font("font","Tabs", default_font ); diff --git a/tools/editor/editor_data.cpp b/tools/editor/editor_data.cpp index c4808d0cadd..7f42f19a9b4 100644 --- a/tools/editor/editor_data.cpp +++ b/tools/editor/editor_data.cpp @@ -432,6 +432,7 @@ int EditorData::add_edited_scene(int p_at_pos) { es.root=NULL; es.history_current=-1; es.version=0; + es.live_edit_root=NodePath(String("/root")); if (p_at_pos==edited_scene.size()) edited_scene.push_back(es); @@ -507,6 +508,31 @@ uint64_t EditorData::get_scene_version(int p_idx) const{ return edited_scene[p_idx].version; } +String EditorData::get_scene_type(int p_idx) const { + + ERR_FAIL_INDEX_V(p_idx,edited_scene.size(),String()); + if (!edited_scene[p_idx].root) + return ""; + return edited_scene[p_idx].root->get_type(); + +} + +Ref