diff options
-rw-r--r-- | builtin/misc.lua | 7 | ||||
-rw-r--r-- | doc/lua_api.txt | 3 | ||||
-rw-r--r-- | src/guiFormSpecMenu.cpp | 122 | ||||
-rw-r--r-- | src/strfnd.h | 37 | ||||
-rw-r--r-- | src/util/string.h | 16 |
5 files changed, 129 insertions, 56 deletions
diff --git a/builtin/misc.lua b/builtin/misc.lua index e018aff85..496435b33 100644 --- a/builtin/misc.lua +++ b/builtin/misc.lua @@ -99,3 +99,10 @@ function minetest.setting_get_pos(name) return minetest.string_to_pos(value) end +function minetest.formspec_escape(str) + str = string.gsub(str, "\\", "\\\\") + str = string.gsub(str, "%[", "\\[") + str = string.gsub(str, "%]", "\\]") + return str +end + diff --git a/doc/lua_api.txt b/doc/lua_api.txt index 005d7c010..8246377e2 100644 --- a/doc/lua_api.txt +++ b/doc/lua_api.txt @@ -778,6 +778,9 @@ string:trim() minetest.pos_to_string({x=X,y=Y,z=Z}) -> "(X,Y,Z)" ^ Convert position to a printable string minetest.string_to_pos(string) -> position +^ Same but in reverse +minetest.formspec_escape(string) -> string +^ escapes characters like [, ], and \ that can not be used in formspecs minetest namespace reference ----------------------------- diff --git a/src/guiFormSpecMenu.cpp b/src/guiFormSpecMenu.cpp index 120d6629a..1754422d0 100644 --- a/src/guiFormSpecMenu.cpp +++ b/src/guiFormSpecMenu.cpp @@ -207,18 +207,18 @@ void GUIFormSpecMenu::regenerateGui(v2u32 screensize) Strfnd f(m_formspec_string); while(f.atend() == false) { - std::string type = trim(f.next("[")); + std::string type = trim(f.next_esc("[")); if(type == "invsize" || type == "size") { v2f invsize; - invsize.X = stof(f.next(",")); + invsize.X = stof(f.next_esc(",")); if(type == "size") { - invsize.Y = stof(f.next("]")); + invsize.Y = stof(f.next_esc("]")); } else{ - invsize.Y = stof(f.next(";")); - f.next("]"); + invsize.Y = stof(f.next_esc(";")); + f.next_esc("]"); } infostream<<"Form size ("<<invsize.X<<","<<invsize.Y<<")"<<std::endl; @@ -242,24 +242,24 @@ void GUIFormSpecMenu::regenerateGui(v2u32 screensize) } else if(type == "list") { - std::string name = f.next(";"); + std::string name = f.next_esc(";"); InventoryLocation loc; if(name == "context" || name == "current_name") loc = m_current_inventory_location; else loc.deSerialize(name); - std::string listname = f.next(";"); + std::string listname = f.next_esc(";"); v2s32 pos = basepos; - pos.X += stof(f.next(",")) * (float)spacing.X; - pos.Y += stof(f.next(";")) * (float)spacing.Y; + pos.X += stof(f.next_esc(",")) * (float)spacing.X; + pos.Y += stof(f.next_esc(";")) * (float)spacing.Y; v2s32 geom; - geom.X = stoi(f.next(",")); - geom.Y = stoi(f.next(";")); + geom.X = stoi(f.next_esc(",")); + geom.Y = stoi(f.next_esc(";")); infostream<<"list inv="<<name<<", listname="<<listname <<", pos=("<<pos.X<<","<<pos.Y<<")" <<", geom=("<<geom.X<<","<<geom.Y<<")" <<std::endl; - std::string start_i_s = f.next("]"); + std::string start_i_s = f.next_esc("]"); s32 start_i = 0; if(start_i_s != "") start_i = stoi(start_i_s); @@ -270,12 +270,12 @@ void GUIFormSpecMenu::regenerateGui(v2u32 screensize) else if(type == "image") { v2s32 pos = basepos; - pos.X += stof(f.next(",")) * (float)spacing.X; - pos.Y += stof(f.next(";")) * (float)spacing.Y; + pos.X += stof(f.next_esc(",")) * (float)spacing.X; + pos.Y += stof(f.next_esc(";")) * (float)spacing.Y; v2s32 geom; - geom.X = stof(f.next(",")) * (float)imgsize.X; - geom.Y = stof(f.next(";")) * (float)imgsize.Y; - std::string name = f.next("]"); + geom.X = stof(f.next_esc(",")) * (float)imgsize.X; + geom.Y = stof(f.next_esc(";")) * (float)imgsize.Y; + std::string name = f.next_esc("]"); infostream<<"image name="<<name <<", pos=("<<pos.X<<","<<pos.Y<<")" <<", geom=("<<geom.X<<","<<geom.Y<<")" @@ -287,12 +287,12 @@ void GUIFormSpecMenu::regenerateGui(v2u32 screensize) else if(type == "item_image") { v2s32 pos = basepos; - pos.X += stof(f.next(",")) * (float)spacing.X; - pos.Y += stof(f.next(";")) * (float)spacing.Y; + pos.X += stof(f.next_esc(",")) * (float)spacing.X; + pos.Y += stof(f.next_esc(";")) * (float)spacing.Y; v2s32 geom; - geom.X = stof(f.next(",")) * (float)imgsize.X; - geom.Y = stof(f.next(";")) * (float)imgsize.Y; - std::string name = f.next("]"); + geom.X = stof(f.next_esc(",")) * (float)imgsize.X; + geom.Y = stof(f.next_esc(";")) * (float)imgsize.Y; + std::string name = f.next_esc("]"); infostream<<"item name="<<name <<", pos=("<<pos.X<<","<<pos.Y<<")" <<", geom=("<<geom.X<<","<<geom.Y<<")" @@ -304,12 +304,12 @@ void GUIFormSpecMenu::regenerateGui(v2u32 screensize) else if(type == "background") { v2s32 pos = basepos; - pos.X += stof(f.next(",")) * (float)spacing.X - ((float)spacing.X-(float)imgsize.X)/2; - pos.Y += stof(f.next(";")) * (float)spacing.Y - ((float)spacing.Y-(float)imgsize.Y)/2; + pos.X += stof(f.next_esc(",")) * (float)spacing.X - ((float)spacing.X-(float)imgsize.X)/2; + pos.Y += stof(f.next_esc(";")) * (float)spacing.Y - ((float)spacing.Y-(float)imgsize.Y)/2; v2s32 geom; - geom.X = stof(f.next(",")) * (float)spacing.X; - geom.Y = stof(f.next(";")) * (float)spacing.Y; - std::string name = f.next("]"); + geom.X = stof(f.next_esc(",")) * (float)spacing.X; + geom.Y = stof(f.next_esc(";")) * (float)spacing.Y; + std::string name = f.next_esc("]"); infostream<<"image name="<<name <<", pos=("<<pos.X<<","<<pos.Y<<")" <<", geom=("<<geom.X<<","<<geom.Y<<")" @@ -320,8 +320,8 @@ void GUIFormSpecMenu::regenerateGui(v2u32 screensize) } else if(type == "field" || type == "textarea") { - std::string fname = f.next(";"); - std::string flabel = f.next(";"); + std::string fname = f.next_esc(";"); + std::string flabel = f.next_esc(";"); if(fname.find(",") == std::string::npos && flabel.find(",") == std::string::npos) { @@ -372,14 +372,14 @@ void GUIFormSpecMenu::regenerateGui(v2u32 screensize) - fname = f.next(";"); - flabel = f.next(";"); + fname = f.next_esc(";"); + flabel = f.next_esc(";"); if(bp_set != 2) errorstream<<"WARNING: invalid use of positioned "<<type<<" without a size[] element"<<std::endl; } - std::string odefault = f.next("]"); + std::string odefault = f.next_esc("]"); std::string fdefault; // fdefault may contain a variable reference, which @@ -389,6 +389,9 @@ void GUIFormSpecMenu::regenerateGui(v2u32 screensize) else fdefault = odefault; + fdefault = unescape_string(fdefault); + flabel = unescape_string(flabel); + FieldSpec spec = FieldSpec( narrow_to_wide(fname.c_str()), narrow_to_wide(flabel.c_str()), @@ -434,15 +437,17 @@ void GUIFormSpecMenu::regenerateGui(v2u32 screensize) else if(type == "label") { v2s32 pos = padding; - pos.X += stof(f.next(",")) * (float)spacing.X; - pos.Y += stof(f.next(";")) * (float)spacing.Y; + pos.X += stof(f.next_esc(",")) * (float)spacing.X; + pos.Y += stof(f.next_esc(";")) * (float)spacing.Y; rect = core::rect<s32>(pos.X, pos.Y+((imgsize.Y/2)-15), pos.X+300, pos.Y+((imgsize.Y/2)+15)); - std::string flabel = f.next("]"); + std::string flabel = f.next_esc("]"); if(bp_set != 2) errorstream<<"WARNING: invalid use of label without a size[] element"<<std::endl; + flabel = unescape_string(flabel); + FieldSpec spec = FieldSpec( narrow_to_wide(""), narrow_to_wide(flabel.c_str()), @@ -455,19 +460,21 @@ void GUIFormSpecMenu::regenerateGui(v2u32 screensize) else if(type == "button" || type == "button_exit") { v2s32 pos = padding; - pos.X += stof(f.next(",")) * (float)spacing.X; - pos.Y += stof(f.next(";")) * (float)spacing.Y; + pos.X += stof(f.next_esc(",")) * (float)spacing.X; + pos.Y += stof(f.next_esc(";")) * (float)spacing.Y; v2s32 geom; - geom.X = (stof(f.next(",")) * (float)spacing.X)-(spacing.X-imgsize.X); - pos.Y += (stof(f.next(";")) * (float)imgsize.Y)/2; + geom.X = (stof(f.next_esc(",")) * (float)spacing.X)-(spacing.X-imgsize.X); + pos.Y += (stof(f.next_esc(";")) * (float)imgsize.Y)/2; rect = core::rect<s32>(pos.X, pos.Y-15, pos.X+geom.X, pos.Y+15); - std::string fname = f.next(";"); - std::string flabel = f.next("]"); + std::string fname = f.next_esc(";"); + std::string flabel = f.next_esc("]"); if(bp_set != 2) errorstream<<"WARNING: invalid use of button without a size[] element"<<std::endl; + flabel = unescape_string(flabel); + FieldSpec spec = FieldSpec( narrow_to_wide(fname.c_str()), narrow_to_wide(flabel.c_str()), @@ -483,20 +490,22 @@ void GUIFormSpecMenu::regenerateGui(v2u32 screensize) else if(type == "image_button" || type == "image_button_exit") { v2s32 pos = padding; - pos.X += stof(f.next(",")) * (float)spacing.X; - pos.Y += stof(f.next(";")) * (float)spacing.Y; + pos.X += stof(f.next_esc(",")) * (float)spacing.X; + pos.Y += stof(f.next_esc(";")) * (float)spacing.Y; v2s32 geom; - geom.X = (stof(f.next(",")) * (float)spacing.X)-(spacing.X-imgsize.X); - geom.Y = (stof(f.next(";")) * (float)spacing.Y)-(spacing.Y-imgsize.Y); + geom.X = (stof(f.next_esc(",")) * (float)spacing.X)-(spacing.X-imgsize.X); + geom.Y = (stof(f.next_esc(";")) * (float)spacing.Y)-(spacing.Y-imgsize.Y); rect = core::rect<s32>(pos.X, pos.Y, pos.X+geom.X, pos.Y+geom.Y); - std::string fimage = f.next(";"); - std::string fname = f.next(";"); - std::string flabel = f.next("]"); + std::string fimage = f.next_esc(";"); + std::string fname = f.next_esc(";"); + std::string flabel = f.next_esc("]"); if(bp_set != 2) errorstream<<"WARNING: invalid use of image_button without a size[] element"<<std::endl; + flabel = unescape_string(flabel); + FieldSpec spec = FieldSpec( narrow_to_wide(fname.c_str()), narrow_to_wide(flabel.c_str()), @@ -519,15 +528,15 @@ void GUIFormSpecMenu::regenerateGui(v2u32 screensize) else if(type == "item_image_button") { v2s32 pos = padding; - pos.X += stof(f.next(",")) * (float)spacing.X; - pos.Y += stof(f.next(";")) * (float)spacing.Y; + pos.X += stof(f.next_esc(",")) * (float)spacing.X; + pos.Y += stof(f.next_esc(";")) * (float)spacing.Y; v2s32 geom; - geom.X = (stof(f.next(",")) * (float)spacing.X)-(spacing.X-imgsize.X); - geom.Y = (stof(f.next(";")) * (float)spacing.Y)-(spacing.Y-imgsize.Y); + geom.X = (stof(f.next_esc(",")) * (float)spacing.X)-(spacing.X-imgsize.X); + geom.Y = (stof(f.next_esc(";")) * (float)spacing.Y)-(spacing.Y-imgsize.Y); rect = core::rect<s32>(pos.X, pos.Y, pos.X+geom.X, pos.Y+geom.Y); - std::string fimage = f.next(";"); - std::string fname = f.next(";"); - std::string flabel = f.next("]"); + std::string fimage = f.next_esc(";"); + std::string fname = f.next_esc(";"); + std::string flabel = f.next_esc("]"); if(bp_set != 2) errorstream<<"WARNING: invalid use of item_image_button without a size[] element"<<std::endl; IItemDefManager *idef = m_gamedef->idef(); @@ -535,6 +544,7 @@ void GUIFormSpecMenu::regenerateGui(v2u32 screensize) item.deSerialize(fimage, idef); video::ITexture *texture = idef->getInventoryTexture(item.getDefinition(idef).name, m_gamedef); std::string tooltip = item.getDefinition(idef).description; + flabel = unescape_string(flabel); FieldSpec spec = FieldSpec( narrow_to_wide(fname.c_str()), narrow_to_wide(flabel.c_str()), @@ -556,7 +566,7 @@ void GUIFormSpecMenu::regenerateGui(v2u32 screensize) else { // Ignore others - std::string ts = f.next("]"); + std::string ts = f.next_esc("]"); infostream<<"Unknown DrawSpec: type="<<type<<", data=\""<<ts<<"\"" <<std::endl; } diff --git a/src/strfnd.h b/src/strfnd.h index d28aa73b2..4a72edf3c 100644 --- a/src/strfnd.h +++ b/src/strfnd.h @@ -65,6 +65,25 @@ public: //std::cout<<"palautus=\""<<palautus<<"\""<<std::endl; return palautus; } + + // Returns substr of tek up to the next occurence of plop that isn't escaped with '\' + std::string next_esc(std::string plop) { + size_t n, realp; + + if (p >= tek.size()) + return ""; + + realp = p; + do { + n = tek.find(plop, p); + if (n == std::string::npos || plop == "") + n = tek.length(); + p = n + plop.length(); + } while (n > 0 && tek[n - 1] == '\\'); + + return tek.substr(realp, n - realp); + } + void skip_over(std::string chars){ while(p < tek.size()){ bool is = false; @@ -128,6 +147,24 @@ public: //std::cout<<"palautus=\""<<palautus<<"\""<<std::endl; return palautus; } + + std::wstring next_esc(std::wstring plop) { + size_t n, realp; + + if (p >= tek.size()) + return L""; + + realp = p; + do { + n = tek.find(plop, p); + if (n == std::wstring::npos || plop == L"") + n = tek.length(); + p = n + plop.length(); + } while (n > 0 && tek[n - 1] == '\\'); + + return tek.substr(realp, n - realp); + } + bool atend(){ if(p>=tek.size()) return true; return false; diff --git a/src/util/string.h b/src/util/string.h index 2f0264bd4..6c48adeb3 100644 --- a/src/util/string.h +++ b/src/util/string.h @@ -286,6 +286,22 @@ inline std::string wrap_rows(const std::string &from, u32 rowlen) return to; } +/* + Removes all \\ from a string that had been escaped (FormSpec strings) +*/ +inline std::string unescape_string(std::string &s) +{ + std::string res; + + for (size_t i = 0; i <= s.length(); i++) { + if (s[i] == '\\') + i++; + res += s[i]; + } + + return res; +} + std::string translatePassword(std::string playername, std::wstring password); size_t curl_write_data(char *ptr, size_t size, size_t nmemb, void *userdata); u32 readFlagString(std::string str, FlagDesc *flagdesc); |