From 177cea995d02fd14dd82fa010957ebfbc1c5e760 Mon Sep 17 00:00:00 2001 From: deva Date: Fri, 17 Jul 2009 13:02:45 +0000 Subject: More work on the macrotool. Now fieldnames can be added and deleted, and a filehandler is able to add new macros assuring no conflicts in macro names/version/filenames happen. Error messages in MacroParser has been made more elaborate. --- server/src/Makefile.am | 2 + server/src/macroparser.cc | 38 +++++-- server/src/macroparser.h | 8 +- server/src/macrotool.cc | 9 +- server/src/macrotool_fieldnames.cc | 30 +++-- server/src/macrotool_filehandler.cc | 218 ++++++++++++++++++++++++++++++++++++ server/src/macrotool_filehandler.h | 36 ++++++ server/src/pracrodaopgsql.cc | 27 +++++ 8 files changed, 348 insertions(+), 20 deletions(-) create mode 100644 server/src/macrotool_filehandler.cc create mode 100644 server/src/macrotool_filehandler.h diff --git a/server/src/Makefile.am b/server/src/Makefile.am index f8f6e21..0589630 100644 --- a/server/src/Makefile.am +++ b/server/src/Makefile.am @@ -48,6 +48,7 @@ macrotool_SOURCES = \ macroparser.cc \ macrotool_dump.cc \ macrotool_fieldnames.cc \ + macrotool_filehandler.cc \ macrotool_util.cc \ pracrodao.cc \ pracrodaopgsql.cc \ @@ -73,6 +74,7 @@ EXTRA_DIST = \ macroparser.h \ macrotool_dump.h \ macrotool_fieldnames.h \ + macrotool_filehandler.h \ macrotool_util.h \ pracrodao.h \ pracrodaopgsql.h \ diff --git a/server/src/macroparser.cc b/server/src/macroparser.cc index c5b524d..0f7ed76 100644 --- a/server/src/macroparser.cc +++ b/server/src/macroparser.cc @@ -28,6 +28,8 @@ #include "macroparser.h" #include "configuration.h" +#include + // For assert #include @@ -56,24 +58,37 @@ void MacroParser::error(const char* fmt, ...) PRACRO_ERR_LOG(macro, "Error in MacroParser: "); - va_list argp; - va_start(argp, fmt); - PRACRO_ERR_LOG_VA(macro, fmt, argp); - va_end(argp); + { + va_list argp; + va_start(argp, fmt); + PRACRO_ERR_LOG_VA(macro, fmt, argp); + va_end(argp); + + fprintf(stderr, "\n"); + } - fprintf(stderr, "\n"); + { + char *p; + va_list argp; + va_start(argp, fmt); + if(vasprintf(&p, fmt, argp) != -1) { + throw Exception("Error in MacroParser: " + std::string(p)); + free(p); + } + va_end(argp); + } - throw Exception("Error in MacroParser"); } -MacroParser::MacroParser(std::string macro) +MacroParser::MacroParser(std::string macro, bool abspath) { state = UNDEFINED; m = NULL; current_map = NULL; current_script = NULL; - file = Conf::xml_basedir + "/macros/" + macro + ".xml"; + if(!abspath) file = Conf::xml_basedir + "/macros/" + macro + ".xml"; + else file = macro; PRACRO_DEBUG(macro, "Using macro file: %s\n", file.c_str()); @@ -298,6 +313,13 @@ void MacroParser::parseError(char *buf, size_t len, std::string error, int linen PRACRO_ERR_LOG(macro, "\tBuffer %u bytes: [", len); if(fwrite(buf, len, 1, stderr) != len) {} PRACRO_ERR_LOG(macro, "]\n"); + + char *slineno; + if(asprintf(&slineno, " at line %d\n", lineno) != -1) { + throw Exception(error + slineno); + free(slineno); + } + } Macro *MacroParser::getMacro() diff --git a/server/src/macroparser.h b/server/src/macroparser.h index 843cb55..3867ca1 100644 --- a/server/src/macroparser.h +++ b/server/src/macroparser.h @@ -45,7 +45,7 @@ class MacroParser : public SAXParser { } ParserState; public: - MacroParser(std::string course); + MacroParser(std::string macro, bool abspath = false); ~MacroParser(); void characterData(std::string &data); @@ -53,6 +53,12 @@ public: void endTag(std::string name); void parseError(char *buf, size_t len, std::string error, int lineno); + /** + * Get a pointer to the parsed macro. + * NOTE: The allocated memory for the macro is owned by the parser, and will be + * freed upon parser deletion. + * @return A pointer to the macro or NULL on error. + */ Macro *getMacro(); protected: diff --git a/server/src/macrotool.cc b/server/src/macrotool.cc index 44beeef..11c634e 100644 --- a/server/src/macrotool.cc +++ b/server/src/macrotool.cc @@ -41,6 +41,7 @@ #include "macrotool_dump.h" #include "macrotool_fieldnames.h" +#include "macrotool_filehandler.h" static const char version_str[] = "Pracro server v" VERSION "\n" @@ -65,9 +66,10 @@ static const char usage_str[] = " -D, --debug ddd Enable debug messages on 'ddd'; see documentation for details\n" "\n" "Commands:\n" -" dump entity Dumps 'entity' to screen ('dump help' to see list of entities).\n" -" fieldnames entity Add/delete/update entries in the fieldnames database\n" -" ('fieldnames help' to see list of entities).\n" +" dump entity Dumps 'entity' to screen ('dump help' to see list of entities).\n" +" fieldnames entity Add/delete/update entries in the fieldnames database\n" +" ('fieldnames help' to see list of entities).\n" +" filehandler entity Handle macro files ('macrohandler help' to see list of entities).\n" ; ConfigurationParser *configparser = NULL; @@ -152,6 +154,7 @@ int main(int argc, char *argv[]) if(command == "dump") macrotool_dump(params); if(command == "fieldnames") macrotool_fieldnames(params); + if(command == "filehandler") macrotool_filehandler(params); // Clean up if(configfile) free(configfile); diff --git a/server/src/macrotool_fieldnames.cc b/server/src/macrotool_fieldnames.cc index eeed648..3c3f8b7 100644 --- a/server/src/macrotool_fieldnames.cc +++ b/server/src/macrotool_fieldnames.cc @@ -37,17 +37,21 @@ static const char usage_str[] = " help Prints this helptext.\n" -" set name desc Add a field (or update) called 'name', described as 'desc'\n" +" add name desc Add a field called 'name', described as 'desc'\n" +" del name Delete a field called 'name'\n" +" list List all fieldnames as well as their macro references.\n" ; static void add(std::string name, std::string desc) { -#ifndef WITHOUT_DB - PRACRO_DEBUG("SET (name: %s - desc: %s)\n", name.c_str(), desc.c_str()); -#else /*WITHOUT_DB*/ - printf("Project not compiled with db spport.") -#endif/*WITHOUT_DB*/ + Database db("pgsql", Conf::database_addr, "", Conf::database_user, Conf::database_passwd, ""); + db.addFieldname(name, desc); +} +static void del(std::string name) +{ + Database db("pgsql", Conf::database_addr, "", Conf::database_user, Conf::database_passwd, ""); + db.delFieldname(name); } static std::vector getWidgetNames(Widget &w) @@ -170,9 +174,9 @@ void macrotool_fieldnames(std::vector params) return; } - if(params[0] == "set") { + if(params[0] == "add") { if(params.size() != 3) { - printf("The command 'set' needs 2 parameters.\n"); + printf("The command 'add' needs 2 parameters.\n"); printf(usage_str); return; } @@ -180,6 +184,16 @@ void macrotool_fieldnames(std::vector params) return; } + if(params[0] == "del") { + if(params.size() != 2) { + printf("The command 'del' needs 1 parameter.\n"); + printf(usage_str); + return; + } + del(params[1]); + return; + } + if(params[0] == "help") { printf(usage_str); return; diff --git a/server/src/macrotool_filehandler.cc b/server/src/macrotool_filehandler.cc new file mode 100644 index 0000000..524761c --- /dev/null +++ b/server/src/macrotool_filehandler.cc @@ -0,0 +1,218 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set et sw=2 ts=2: */ +/*************************************************************************** + * macrotool_filehandler.cc + * + * Fri Jul 17 08:48:09 CEST 2009 + * Copyright 2009 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 "macrotool_filehandler.h" + +#include +#include + +#include "macroparser.h" +#include "template.h" + +#include "debug.h" + +#include "macrotool_util.h" + +#include "configuration.h" + +static const char usage_str[] = +" help Prints this helptext.\n" +" add file Add a file called 'file' to the macro or template folder, according\n" +" to its contents.\n" +" check file Check if a file is valid, and print a resume of its contents.\n" +; + +/** +class Macro { +public: + std::vector< Query > queries; + std::vector< Map > maps; + std::vector< Script > scripts; + Widget window; + std::map< std::string, std::string > attributes; + Resume resume; +}; + **/ +static bool check(std::string file, std::string *name = NULL, std::string *version = NULL); +static bool check(std::string file, std::string *name, std::string *version) +{ + try { + MacroParser parser(file, true); + parser.parse(); + Macro *macro = parser.getMacro(); + if(!macro) { + printf("Macro malformed!\n"); + return false; + } + + printf("Parsing of %s was succesful.\n", file.c_str()); + printf("Name: %s\n", macro->attributes["name"].c_str()); + printf("Version: %s\n", macro->attributes["version"].c_str()); + + if(name) *name = macro->attributes["name"]; + if(version) *version = macro->attributes["version"]; + + } catch( std::exception &e ) { + printf("%s\n", e.what()); + return false; + } + return true; +} + +static bool macro_exists(std::string name, std::string version, std::string &clashfile) +{ + std::vector macrofiles = getMacros(); + std::vector::iterator mfs = macrofiles.begin(); + while(mfs != macrofiles.end()) { + std::string macroname = mfs->substr(0, mfs->length() - 4); + + MacroParser parser(macroname); + parser.parse(); + Macro *macro = parser.getMacro(); + + if(name == macro->attributes["name"] && + version == macro->attributes["version"]) { + clashfile = *mfs; + return true; + } + + mfs++; + } + + return false; +} + +static std::string strippath(std::string filename) +{ + if(filename.find('/') == std::string::npos) return filename; + return filename.substr(filename.rfind('/')+1); +} + +static bool file_exist(std::string file) +{ + FILE *fp = fopen(file.c_str(), "r"); + if(!fp) return false; + fclose(fp); + return true; +} + +static void add(std::string file) +{ + std::string name; + std::string version; + std::string clashfile; + std::string target; + + if(!check(file, &name, &version)) { + printf("File not a valid macro file.\nAborting...\n"); + return; + } + + if(macro_exists(name, version, clashfile)) { + printf("WARNING: A macro with that name and version already exists." + " THE EXISTING FILE WILL BE OVERWRITTEN!\n"); + printf("File: %s\n", clashfile.c_str()); + char answer[32]; + answer[0] = '\0'; + while(std::string(answer) != "yes\n" && std::string(answer) != "no\n") { + if(answer[0] == '\0') printf("Are you sure you want to put the file in the macro directory? [yes/no]\n"); + else printf("Please answer 'yes' or 'no'\n"); + fgets(answer, sizeof(answer), stdin); + } + + if(std::string(answer) == "no\n") { + printf("Aborting...\n"); + return; + } + target = Conf::xml_basedir + "/macros/" + clashfile; + } else { + target = Conf::xml_basedir + "/macros/" + strippath(file); + + size_t cnt = 0; + while(file_exist(target)) { + char *num; + if(cnt) asprintf(&num, "-%d", cnt); + else num = strdup(""); + target = Conf::xml_basedir + "/macros/" + name + "-" + version + num + ".xml"; + printf("Trying: %d %s\n", cnt, target.c_str()); + free(num); + cnt++; + } + } + + printf("Copying '%s' to '%s' ...\n", file.c_str(), target.c_str()); + + { + std::ifstream ifs(file.c_str(), std::ios::binary); + if(!ifs) { + printf("Could read source file.\nAborting...\n"); + return; + } + std::ofstream ofs(target.c_str(), std::ios::binary); + ofs << ifs.rdbuf(); + } + printf("done\n"); +} + +void macrotool_filehandler(std::vector params) +{ + if(params.size() < 1) { + printf(usage_str); + return; + } + + PRACRO_DEBUG(filehandler, "filehandler: %s\n", params[0].c_str()); + + if(params[0] == "add") { + if(params.size() != 2) { + printf("The command 'add' needs 1 parameter.\n"); + printf(usage_str); + return; + } + add(params[1]); + return; + } + + if(params[0] == "check") { + if(params.size() != 2) { + printf("The command 'check' needs 1 parameter.\n"); + printf(usage_str); + return; + } + check(params[1]); + return; + } + + if(params[0] == "help") { + printf(usage_str); + return; + } + + printf("Unknown command '%s'\n", params[0].c_str()); + printf(usage_str); + return; +} diff --git a/server/src/macrotool_filehandler.h b/server/src/macrotool_filehandler.h new file mode 100644 index 0000000..70777fc --- /dev/null +++ b/server/src/macrotool_filehandler.h @@ -0,0 +1,36 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set et sw=2 ts=2: */ +/*************************************************************************** + * macrotool_filehandler.h + * + * Fri Jul 17 08:48:09 CEST 2009 + * Copyright 2009 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_MACROTOOL_FILEHANDLER_H__ +#define __PRACRO_MACROTOOL_FILEHANDLER_H__ + +#include +#include + +void macrotool_filehandler(std::vector params); + +#endif/*__PRACRO_MACROTOOL_FILEHANDLER_H__*/ diff --git a/server/src/pracrodaopgsql.cc b/server/src/pracrodaopgsql.cc index 683fe85..7159b03 100644 --- a/server/src/pracrodaopgsql.cc +++ b/server/src/pracrodaopgsql.cc @@ -244,10 +244,37 @@ unsigned PracroDAOPgsql::nrOfCommits(std::string patientid, std::string macronam void PracroDAOPgsql::addFieldname(std::string name, std::string description) { + std::stringstream timestamp; timestamp << time(NULL); + std::string ts; + try { + pqxx::work W(*conn); + ts = "INSERT INTO fieldnames (name, description, \"timestamp\") VALUES (" + " '" + W.esc(name) + "', " + " '" + W.esc(description) + "', " + " '" + W.esc(timestamp.str()) + "' " + ")" + ; + PRACRO_DEBUG(sql, "Query: %s\n", ts.c_str()); + pqxx::result R = W.exec(ts); + W.commit(); + } catch (std::exception &e) { + PRACRO_ERR_LOG(db, "Query failed: %s: %s\n", e.what(), ts.c_str()); + } } void PracroDAOPgsql::delFieldname(std::string name) { + std::string ts; + try { + pqxx::work W(*conn); + ts = "DELETE FROM fieldnames WHERE name=" + "'" + W.esc(name) + "' "; + PRACRO_DEBUG(sql, "Query: %s\n", ts.c_str()); + pqxx::result R = W.exec(ts); + W.commit(); + } catch (std::exception &e) { + PRACRO_ERR_LOG(db, "Query failed: %s: %s\n", e.what(), ts.c_str()); + } } std::vector PracroDAOPgsql::getFieldnames() -- cgit v1.2.3