/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* vim: set et sw=2 ts=2: */ /*************************************************************************** * msgparser.cc * * Fri Feb 24 14:59:34 CET 2012 * Copyright 2012 Jonas Suhr Christensen * jsc@umbraculum.org ****************************************************************************/ /* * This file is part of Munia. * * Munia 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. * * Munia 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 Munia; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ #include "messageparser.h" #include #include #include #include typedef std::vector TokenVector; typedef std::list MsgTokensList; inline static void parse_into_msg_tokens(std::string& data, MsgTokensList& msgTokensList) { TokenVector tokenVector; std::string token; bool inside_quote = false; char prev_ch = '0'; for(size_t i = 0; i < data.length(); i++) { char ch = data[i]; switch(ch) { case '\"': if(prev_ch != '\\') inside_quote = !inside_quote; else { token += ch; } break; case ' ': if(inside_quote) { //printf("Appending %c\n", ch); token += ch; } else { if(token.empty()) continue; // skip multiple white spaces and pre white space // printf("Adding token %s\n", token.c_str()); tokenVector.push_back(token); token.clear(); } break; case ';': if(inside_quote) { token += ch; } else { tokenVector.push_back(token); msgTokensList.push_back(tokenVector); tokenVector.clear(); token.clear(); } break; default: token += ch; break; } prev_ch = ch; } // if(!token.empty()) { tokenVector.push_back(token); token.clear(); // } if(!tokenVector.empty()) { msgTokensList.push_back(tokenVector); tokenVector.clear(); } } #include static taskid_t baseid = 10000; static taskid_t getId(std::map &sym, std::string token) { bool isnumeric = true; for(size_t i = 0; i < token.size(); i++) { isnumeric &= (token[i] >= '0' && token[i] <= '9'); } if(isnumeric) return atoi(token.c_str()); if(sym.find(token) == sym.end()) sym[token] = baseid++; return sym[token]; } inline static void create_msg_list(MsgTokensList& msgTokensList, MessageList& msgList, bool clientmode) { size_t origin = 0; if(clientmode) { origin = 1; } std::map sym; MsgTokensList::iterator it_msg; for(it_msg = msgTokensList.begin(); it_msg != msgTokensList.end(); it_msg++) { TokenVector t = *it_msg; //malformed msg if(t.size() < origin+1) continue; message_t m; printf("t[%d] : %s, running in clientmode: %d\n", origin, t[origin].c_str(), clientmode); // printf("%d\n", t.size()); if(t[origin] == "observe") m.cmd = cmd::observe; else if(t[origin] == "unobserve") m.cmd = cmd::unobserve; else if(t[origin] == "create") m.cmd = cmd::create; else if(t[origin] == "remove") m.cmd = cmd::remove; else if(t[origin] == "move") m.cmd = cmd::move; else if(t[origin] == "update") m.cmd = cmd::update; else m.cmd = cmd::error; // printf("Number of tokens %d\n", t.size()); switch(m.cmd) { case cmd::observe: { if(t.size() != origin+1+1) { printf("Wrong number of parameters\n"); continue; } m.observe.id = getId(sym, t[origin+1]);//atoi(t[origin+1].c_str()); break; } case cmd::unobserve: { if(t.size() != origin+1+1) { printf("Wrong number of parameters\n"); continue; } m.unobserve.id = getId(sym, t[origin+1]);//atoi(t[origin+1].c_str()); break; } case cmd::create: { if(!clientmode && t.size() != origin+1+2) { printf("Wrong number of parameters\n"); continue; } if(clientmode && t.size() != origin+1+2) { printf("Wrong number of parameters\n"); continue; } if(clientmode) { m.create.id = getId(sym, t[origin+1]);//atoi(t[origin+1].c_str()); m.create.parentid = getId(sym, t[origin+2]);// atoi(t[origin+2].c_str()); } else { m.create.id = getId(sym, t[origin+1]);//atoi(t[origin+1].c_str()); m.create.parentid = getId(sym, t[origin+2]);//atoi(t[origin+1].c_str()); } break; } case cmd::remove: { if(t.size() != origin+1+1) { printf("Wrong number of parameters\n"); continue; } m.remove.id = getId(sym, t[origin+1]);//atoi(t[origin+1].c_str()); break; } case cmd::move: { if(t.size() != origin+2+1) { printf("Wrong number of parameters\n"); continue; } m.move.id = getId(sym, t[origin+1]);//atoi(t[origin+1].c_str()); m.move.parentid = getId(sym, t[origin+2]);//atoi(t[origin+2].c_str()); break; } case cmd::update: { if(t.size() != origin+2+1) { printf("Wrong number of parameters\n"); continue; } m.update.id = getId(sym, t[origin+1]);//atoi(t[origin+1].c_str()); sprintf(m.update.title, "%s", t[origin+2].c_str()); break; } default: break; }; msgList.push_back(m); } } MessageList parse_msg(std::string data) { printf("Parsing: %s\n", data.c_str()); MsgTokensList msgTokensList; parse_into_msg_tokens(data, msgTokensList); MessageList msgList; create_msg_list(msgTokensList, msgList, false); return msgList; } MessageList parse_msg_client(std::string data) { printf("Parsing: \n%s\n", data.c_str()); MsgTokensList msgTokensList; parse_into_msg_tokens(data, msgTokensList); MessageList msgList; create_msg_list(msgTokensList, msgList, true); return msgList; } std::string msg_tostring(message_t m) { char* buf = NULL; switch(m.cmd) { case cmd::create: { asprintf(&buf, "create %d %d;", m.create.id, m.create.parentid); break; } case cmd::remove: { asprintf(&buf, "remove %d;", m.remove.id); break; } case cmd::move: { asprintf(&buf, "move %d %d;", m.move.id, m.move.parentid); break; } case cmd::update: { asprintf(&buf, "update %d \"%s\";", m.update.id, m.update.title); break; }; default: break; } std::string r; if(buf) { r = buf; free(buf); } return r; } message_t create_msg_create(task_t t) { message_t m; m.cmd = cmd::create; m.create.id = t.id; m.create.parentid = t.parentid; return m; } message_t create_msg_update(task_t t) { message_t m; m.cmd = cmd::update; m.update.id = t.id; sprintf(m.update.title, "%s", t.title.c_str()); return m; } message_t create_msg_remove(task_t t) { message_t m; m.cmd = cmd::remove; m.remove.id = t.id; return m; } message_t create_msg_move(taskid_t id, taskid_t to) { message_t m; m.cmd = cmd::move; m.move.id = id; m.move.parentid = to; return m; } #ifdef TEST_MSGPARSER //Additional dependency files //deps: //Required cflags (autoconf vars may be used) //cflags: //Required link options (autoconf vars may be used) //libs: #include "test.h" TEST_BEGIN; // TODO: Put some testcode here (see test.h for usable macros). TEST_TRUE(false, "No tests yet!"); TEST_END; #endif/*TEST_MSGPARSER*/