summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorkwolekr <kwolekr@minetest.net>2013-02-24 16:00:35 -0500
committerkwolekr <kwolekr@minetest.net>2013-03-05 23:25:02 -0500
commitba78194636a9a498f6979cc21cd39399f23d658a (patch)
tree7cad8f0234fe4f7ff45807364b4c275296982805
parentbdbdeab0053d9ebbaffea17effeba777b710d390 (diff)
downloadminetest-ba78194636a9a498f6979cc21cd39399f23d658a.tar.gz
minetest-ba78194636a9a498f6979cc21cd39399f23d658a.tar.bz2
minetest-ba78194636a9a498f6979cc21cd39399f23d658a.zip
Allow any character in formspec strings with escape char
-rw-r--r--builtin/misc.lua7
-rw-r--r--doc/lua_api.txt3
-rw-r--r--src/guiFormSpecMenu.cpp122
-rw-r--r--src/strfnd.h37
-rw-r--r--src/util/string.h16
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);