diff options
-rw-r--r-- | server/src/Makefile.am | 6 | ||||
-rw-r--r-- | server/src/formattools.cc | 137 | ||||
-rw-r--r-- | server/src/formattools.h | 7 | ||||
-rw-r--r-- | server/src/luaformatmapper.cc | 119 | ||||
-rw-r--r-- | server/src/luaformatmapper.h | 58 |
5 files changed, 318 insertions, 9 deletions
diff --git a/server/src/Makefile.am b/server/src/Makefile.am index 378c9bd..3449e6b 100644 --- a/server/src/Makefile.am +++ b/server/src/Makefile.am @@ -17,6 +17,7 @@ pracrod_SOURCES = \ queryparser.cc \ journal_commit.cc \ log.cc \ + luaformatmapper.cc \ luaquerymapper.cc \ macroparser.cc \ resumeparser.cc \ @@ -40,6 +41,7 @@ EXTRA_DIST = \ queryparser.h \ journal_commit.h \ log.h \ + luaformatmapper.h \ luaquerymapper.h \ macroparser.h \ resumeparser.h \ @@ -71,8 +73,8 @@ test: $(TESTFILES) test_clean: rm -f $(TESTFILES) -test_formattools: formattools.cc - @../../tools/test formattools.cc +test_formattools: formattools.cc luaformatmapper.cc + @../../tools/test formattools.cc luaformatmapper.cc exception.cc log.cc $(LUA_LIBS) test_queryhandler: queryhandler.cc @../../tools/test queryhandler.cc tcpsocket.cc exception.cc log.cc diff --git a/server/src/formattools.cc b/server/src/formattools.cc index 883f6ba..b90ca51 100644 --- a/server/src/formattools.cc +++ b/server/src/formattools.cc @@ -26,6 +26,8 @@ */ #include "formattools.h" +#include "luaformatmapper.h" + /** * Replace all ocurrences of c with cc. */ @@ -39,6 +41,22 @@ static std::string escape_string(std::string str, char c) return out; } +/** + * Replace all ocurrences of cc with c. + */ +static std::string deescape_string(std::string str, char c) +{ + std::string out; + for(size_t i = 0; i < str.length(); i++) { + if(i < str.length() - 1 && str[i] == c && str[i + 1] == c) { + // We simply do nothing here, thus skipping the current character. + } else { + out += str[i]; + } + } + return out; +} + std::string escape_multilist_string(std::string str) { return escape_string(escape_string(str, '{'), '}'); @@ -49,29 +67,138 @@ std::string escape_resume_string(std::string str) return escape_string(escape_string(str, '['), ']'); } -std::map<std::string, std::string> get_multilist_values(std::string str) +// FIXME: This function doesn't work... reimplement using regexps. +Fields get_multilist_values(std::string str) { std::map<std::string, std::string> values; + + // Replace ${foo|bar} with bar + for(size_t i = 0; i < str.length(); i++) { + if(str[i] == '$') { + if(i < str.length() - 2 && + str[i+1] == '{' && str[i+2] != '{') { + // We are in a key/value + + // Look for end marker, and | + size_t j; + for(j = i + 2; j < str.length(); j++) { + if(str[j] == '}' && str[j + 1] != '}') { + // We have an end marker + break; + } + } + + std::string key_value = str.substr(i + 2, j - (i + 2)); + printf("Found [%s]\n", key_value.c_str()); + + std::string value = key_value.substr(key_value.find('|') + 1); + std::string key = key_value.substr(0, key_value.find('|') - 1); + + values[key] = value; + + i = j; + + } + } + } + return values; } + +// FIXME: This function doesn't work... reimplement using regexps. std::string render_multilist_string(std::string str) { - return str; + std::string out; + + // Replace ${foo|bar} with bar + for(size_t i = 0; i < str.length(); i++) { + if(str[i] == '$') { + if(i < str.length() - 2 && + str[i+1] == '{' && str[i+2] != '{') { + // We are in a key/value + + // Look for end marker, and | + size_t j; + for(j = i + 2; j < str.length(); j++) { + if(str[j] == '}' && str[j + 1] != '}') { + // We have an end marker + break; + } + } + + std::string key_value = str.substr(i + 2, j - (i + 2)); + printf("Found [%s]\n", key_value.c_str()); + + std::string value = key_value.substr(key_value.find('|') + 1); + + out += value; + + i = j; + + } else out += str[i]; + } else { + out += str[i]; + } + } + + return deescape_string(deescape_string(out, '{'), '}'); } -std::string render_resume_string(std::string str) +std::string render_resume_string(std::string str, Fields &fields) { - return str; + std::string out; + + LUAFormatMapper mapper(fields); + + // Replace ${foo|bar} with bar + for(size_t i = 0; i < str.length(); i++) { + if(str[i] == '$') { + if(i < str.length() - 2 && + str[i+1] == '[' && str[i+2] != '[') { + // We are in a key/value + + // Look for end marker, and | + size_t j; + for(j = i + 2; j < str.length(); j++) { + if(str[j] == ']' && str[j + 1] != ']') { + // We have an end marker + break; + } + } + + std::string luaprogram = str.substr(i + 2, j - (i + 2)); + printf("Found [%s]\n", luaprogram.c_str()); + + std::string value = mapper.map(luaprogram); + + out += value; + + i = j; + + } else out += str[i]; + } else { + out += str[i]; + } + } + + return deescape_string(deescape_string(out, '['), ']'); } #ifdef TEST_FORMATTOOLS int main() { + Fields fields; + fields["dingo"] = "[[meget dyr]]"; + fields["fnuld"] = "Zimbabwe"; + + printf("%s\n", deescape_string(deescape_string("[[] []]", '['), ']').c_str()); + if(escape_multilist_string("${} {{}}") != "${{}} {{{{}}}}") return 1; if(escape_resume_string("$[] [[]]") != "$[[]] [[[[]]]]") return 1; - + printf("{%s}\n", render_multilist_string("Ladidaa ${foo|bar} ${{dingo|dyt}} ${dims|dulle}.").c_str()); + printf("{%s}\n", render_resume_string("Ladidaa $[return 'dims' .. dingo] $[[et eller andet]] $[return 'noget andet'].", fields).c_str()); return 0; } diff --git a/server/src/formattools.h b/server/src/formattools.h index fcfb372..5bad492 100644 --- a/server/src/formattools.h +++ b/server/src/formattools.h @@ -30,6 +30,9 @@ #include <string> #include <map> +// For Fields +#include "transaction.h" + /** * Escape all { and } characters. */ @@ -43,7 +46,7 @@ std::string escape_resume_string(std::string str); /** * Get name/value pair list from multilist result string. */ -std::map<std::string, std::string> get_multilist_values(std::string str); +Fields get_multilist_values(std::string str); /** * Render tekst from multilist result string, by inserting the values at the @@ -55,6 +58,6 @@ std::string render_multilist_string(std::string str); * Render resume tekst, by running the embedded LUA code and replacing the ${...} * placeholders with the output and de-escaping {{ and }}. */ -std::string render_resume_string(std::string str); +std::string render_resume_string(std::string str, Fields &fields); #endif/*__PRACRO_FORMATTOOLS_H__*/ diff --git a/server/src/luaformatmapper.cc b/server/src/luaformatmapper.cc new file mode 100644 index 0000000..b45c170 --- /dev/null +++ b/server/src/luaformatmapper.cc @@ -0,0 +1,119 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/*************************************************************************** + * luaformatmapper.cc + * + * Wed Oct 29 16:02:03 CET 2008 + * Copyright 2008 Bent Bisballe Nyeng + * deva@aasimon.org + ****************************************************************************/ + +/* + * This file is part of Pracro. + * + * Pracro is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * Pracro is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Pracro; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ +#include "luaformatmapper.h" + +#include <sstream> + +#include "exception.h" + +static std::string loadresultstring(Fields &fields) +{ + std::string s; + + Fields::iterator v = fields.begin(); + while(v != fields.end()) { + s += (*v).first + " = \"" + (*v).second + "\"\n"; + v++; + } + + return s; +} + +LUAFormatMapper::LUAFormatMapper(Fields &fields) +{ + L = luaL_newstate(); + if(L == NULL) { + error("Could not create LUA state."); + return; + } + + luaL_openlibs(L); + + std::string preload = loadresultstring(fields); + + if(luaL_loadbuffer(L, preload.c_str(), preload.size(), "preload")) { + error(lua_tostring(L, lua_gettop(L))); + return; + } + + // Run program (init) + if(lua_pcall(L, 0, LUA_MULTRET, 0)) { + error(lua_tostring(L, lua_gettop(L))); + return; + } + + clean_top = lua_gettop(L); +} + +LUAFormatMapper::~LUAFormatMapper() +{ + lua_close(L); +} + +std::string LUAFormatMapper::map(const std::string &mapper) +{ + output = ""; + + if(L == NULL) { + error("LUA state not initialized!"); + return output; + } + + if(mapper == "") { + error("Empty LUA mapper detected in " + mapper); + return output; + } + + // Load the mapper + if(luaL_loadbuffer(L, mapper.c_str(), mapper.size(), "mapper")) { + error(lua_tostring(L, lua_gettop(L)) + std::string(" in ") + mapper); + return output; + } + + // Run the loaded code + if(lua_pcall(L, 0, LUA_MULTRET, 0)) { + error(lua_tostring(L, lua_gettop(L)) + std::string(" in ") + mapper); + return output; + } + + // Check if app messed up the stack. + if(lua_gettop(L) != clean_top + 1) { + error("Wrong number of return values in " + mapper); + lua_pop(L, lua_gettop(L) - clean_top); + return output; + } + + output = lua_tostring(L, lua_gettop(L)); + lua_pop(L, 1); + + return output; +} + +void LUAFormatMapper::error(std::string message) +{ + throw Exception("ERROR in LUAFormatMapper: " + message); +} diff --git a/server/src/luaformatmapper.h b/server/src/luaformatmapper.h new file mode 100644 index 0000000..b4cb8c9 --- /dev/null +++ b/server/src/luaformatmapper.h @@ -0,0 +1,58 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/*************************************************************************** + * luaformatmapper.h + * + * Wed Oct 29 16:02:03 CET 2008 + * Copyright 2008 Bent Bisballe Nyeng + * deva@aasimon.org + ****************************************************************************/ + +/* + * This file is part of Pracro. + * + * Pracro is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * Pracro is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Pracro; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ +#ifndef __PRACRO_LUAFORMATMAPPER_H__ +#define __PRACRO_LUAFORMATMAPPER_H__ + +#include "transaction.h" + +#include <lua.hpp> +#include <lauxlib.h> + +/** + * The LUAQueryMapper class takes the result of an external data query and + * applies the associated map. + */ +class LUAFormatMapper { +public: + LUAFormatMapper(Fields &fields); + ~LUAFormatMapper(); + + /** + * Applies the mapping program to the result-namespace, and returns the + * resulting value. + */ + std::string map(const std::string &mapper); + + void error(std::string message); + +private: + lua_State *L; + int clean_top; + std::string output; +}; + +#endif/*__PRACRO_LUAFORMATMAPPER_H__*/ |