zorba-coders team mailing list archive
-
zorba-coders team
-
Mailing list archive
-
Message #02784
[Merge] lp:~zorba-coders/zorba/debugger_client into lp:zorba
Gabriel Petrovay has proposed merging lp:~zorba-coders/zorba/debugger_client into lp:zorba.
Requested reviews:
Markos Zaharioudakis (markos-za)
Juan Zacarias (juan457)
Related bugs:
Bug #867377 in Zorba: "Add debugger client command line execution support"
https://bugs.launchpad.net/zorba/+bug/867377
Bug #898093 in Zorba: "Debugger: print source code of current line in debugger client"
https://bugs.launchpad.net/zorba/+bug/898093
Bug #898575 in Zorba: "Debugger: crash when breakpoint remove"
https://bugs.launchpad.net/zorba/+bug/898575
Bug #898578 in Zorba: "Debugger: breakpoint not removed from runtime during execution"
https://bugs.launchpad.net/zorba/+bug/898578
Bug #898580 in Zorba: "Debugger: starting query with "over" blocks the debugger client"
https://bugs.launchpad.net/zorba/+bug/898580
Bug #898593 in Zorba: "Debugger: query body not always breakable"
https://bugs.launchpad.net/zorba/+bug/898593
Bug #901676 in Zorba: "Clean the URIHelper decodeFileURI & encodeFileURI mess iin debugger_runtime.cpp"
https://bugs.launchpad.net/zorba/+bug/901676
For more details, see:
https://code.launchpad.net/~zorba-coders/zorba/debugger_client/+merge/85471
The mature debugger client.
--
https://code.launchpad.net/~zorba-coders/zorba/debugger_client/+merge/85471
Your team Zorba Coders is subscribed to branch lp:zorba.
=== modified file 'CMakeConfiguration.txt'
--- CMakeConfiguration.txt 2011-09-16 19:55:59 +0000
+++ CMakeConfiguration.txt 2011-12-13 11:51:46 +0000
@@ -70,10 +70,6 @@
SET(ZORBA_FOR_ONE_THREAD_ONLY OFF CACHE BOOL "compile zorba for single threaded use")
MESSAGE(STATUS "ZORBA_FOR_ONE_THREAD_ONLY: " ${ZORBA_FOR_ONE_THREAD_ONLY})
-# by default the zorba command line client is deactivated until it gets to a more stable and userfriendly state
-SET(ZORBA_WITH_DEBUGGER_CLIENT OFF CACHE BOOL "build and install zorbas command line debugger client")
-MESSAGE(STATUS "ZORBA_WITH_DEBUGGER_CLIENT: " ${ZORBA_WITH_DEBUGGER_CLIENT})
-
IF (DEFINED UNIX)
IF (NOT DEFINED ZORBA_HAVE_PTHREAD_H AND NOT DEFINED ZORBA_FOR_ONE_THREAD_ONLY)
MESSAGE(FATAL_ERROR "pthread is not available")
=== modified file 'bin/CMakeLists.txt'
--- bin/CMakeLists.txt 2011-11-04 11:40:20 +0000
+++ bin/CMakeLists.txt 2011-12-13 11:51:46 +0000
@@ -15,26 +15,15 @@
INCLUDE_DIRECTORIES(AFTER ${CMAKE_SOURCE_DIR}/src/)
INCLUDE_DIRECTORIES(AFTER ${CMAKE_CURRENT_SOURCE_DIR})
-IF(ZORBA_WITH_DEBUGGER_CLIENT)
- CONFIGURE_FILE (debug_client/event_handler_init.cpp.in debug_client/event_handler_init.cpp)
-
- SET(DEBUG_CLIENT_SRCS
- debug_client/tuple.h
- debug_client/main.cpp
- debug_client/debug_command.h
- debug_client/debug_command.cpp
- debug_client/command_line_handler.h
- debug_client/command_line_handler.cpp
- debug_client/lock_free_queue.h
- debug_client/event_handler.h
- debug_client/event_handler.cpp
- ${CMAKE_CURRENT_BINARY_DIR}/debug_client/event_handler_init.cpp
+IF (ZORBA_WITH_DEBUGGER)
+ SET (DEBUG_CLIENT_SRCS
+ debugger/main.cpp
+ debugger/command_prompt.cpp
+ debugger/command_line_handler.cpp
+ debugger/event_handler.cpp
)
-
- CONFIGURE_FILE (debug_client/message-handler.xq message-handler.xq)
-
- ZORBA_GENERATE_EXE("debuggercmd" "${DEBUG_CLIENT_SRCS}" "" "debugger" "bin")
-ENDIF(ZORBA_WITH_DEBUGGER_CLIENT)
+ ZORBA_GENERATE_EXE ("xqdb" "${DEBUG_CLIENT_SRCS}" "" "xqdb" "bin")
+ENDIF (ZORBA_WITH_DEBUGGER)
SET(SRCS
zorbacmd.cpp
=== removed file 'bin/debug_client/debug_command.cpp'
--- bin/debug_client/debug_command.cpp 2011-07-01 01:53:24 +0000
+++ bin/debug_client/debug_command.cpp 1970-01-01 00:00:00 +0000
@@ -1,99 +0,0 @@
-/*
- * Copyright 2006-2008 The FLWOR Foundation.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#include <iostream>
-#include "debug_client/debug_command.h"
-
-namespace zorba { namespace debugclient {
-
-
- void CommandLine::execute()
- {
- for (;;) {
- std::cout << "zdb>> ";
- std::string command;
- std::getline(std::cin, command);
- std::vector<std::string> args;
- args << command;
- std::map<std::string, UntypedCommand*>::iterator lIter = theCommands.find(args[0]);
- if (lIter == theCommands.end()) {
- std::cout << args[0] << ": Command not found" << std::endl;
- continue;
- }
- if (!lIter->second->execute(args))
- continue;
- return;
- }
- }
-
-
- CommandLine::~CommandLine()
- {
- for (std::map<std::string, UntypedCommand*>::iterator i = theCommands.begin();
- i != theCommands.end(); ++i)
- {
- delete i->second;
- }
- }
-
- CommandLine& CommandLine::operator<<(UntypedCommand *aCommand)
- {
- theCommands.insert(std::make_pair(aCommand->get_name(), aCommand));
- return *this;
- }
-}}
-
-namespace std {
- vector<string>& operator<< (vector<string>& vec, const string& str)
- {
- string::size_type before = 0;
- string::size_type pos = str.find(" ", 0);
- while (pos != str.npos) {
- std::string lSub = str.substr(before, pos - before);
- if (lSub[0] == '"') {
- std::string::size_type lBeforeCopy = before;
- do {
- lBeforeCopy = str.find("\"", lBeforeCopy + 1);
- } while (pos != str.npos && str.size() > pos + 1 && str[pos + 1] == '\\');
- pos = lBeforeCopy;
- lSub = str.substr(before + 1, pos - before - 1);
- }
- vec.push_back(lSub);
- before = pos + 1;
- pos = str.find(" ", before);
- }
- std::string lSub = str.substr(before);
- if (lSub[0] == '"') {
- pos = str.find("\"", before + 1);
- lSub = str.substr(before + 1, pos - before - 1);
- }
- vec.push_back(lSub);
- return vec;
- }
-
- set<string>& operator<< (set<string>& vec, const string& str)
- {
- string::size_type before = 0;
- string::size_type pos = str.find(" ", 0);
- while (pos != str.npos) {
- vec.insert(str.substr(before, pos));
- before = pos + 1;
- pos = str.find(" ", before);
- }
- vec.insert(str.substr(before));
- return vec;
- }
-
-}
=== removed file 'bin/debug_client/event_handler_init.cpp.in'
--- bin/debug_client/event_handler_init.cpp.in 2011-07-01 01:53:24 +0000
+++ bin/debug_client/event_handler_init.cpp.in 1970-01-01 00:00:00 +0000
@@ -1,41 +0,0 @@
-/*
- * Copyright 2006-2008 The FLWOR Foundation.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#include <fstream>
-#include "debug_client/event_handler.h"
-
-namespace zorba { namespace debugclient {
-
- std::istream* EventHandler::getCurrentDirectory() {
- const char* build_dir = "@CMAKE_BINARY_DIR@/bin/message-handler.xq";
- const char* install_dir =
-#ifndef WIN32
- "@CMAKE_INSTALL_PREFIX@/bin/";
-#else
- "C:/Program Files/Zorba XQuery Processor @ZORBA_MAJOR_NUMBER@.@ZORBA_MINOR_NUMBER@.@ZORBA_PATCH_NUMBER@/bin/";
-#endif
- std::auto_ptr<std::ifstream> stream(new std::ifstream(build_dir));
- if (stream->good()) {
- return stream.release();
- }
- stream.reset(new std::ifstream(install_dir));
- if (stream->good()) {
- return stream.release();
- }
- return 0;
- }
-
-}} // end of namespace zorba::debugclient
-
=== removed file 'bin/debug_client/lock_free_queue.cpp'
--- bin/debug_client/lock_free_queue.cpp 2011-07-01 01:53:24 +0000
+++ bin/debug_client/lock_free_queue.cpp 1970-01-01 00:00:00 +0000
@@ -1,16 +0,0 @@
-/*
- * Copyright 2006-2008 The FLWOR Foundation.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#include "lock_free_queue.h"
=== removed file 'bin/debug_client/message-handler.xq'
--- bin/debug_client/message-handler.xq 2011-08-26 23:36:24 +0000
+++ bin/debug_client/message-handler.xq 1970-01-01 00:00:00 +0000
@@ -1,165 +0,0 @@
-(:
- : Copyright 2006-2009 The FLWOR Foundation.
- :
- : Licensed under the Apache License, Version 2.0 (the "License");
- : you may not use this file except in compliance with the License.
- : You may obtain a copy of the License at
- :
- : http://www.apache.org/licenses/LICENSE-2.0
- :
- : Unless required by applicable law or agreed to in writing, software
- : distributed under the License is distributed on an "AS IS" BASIS,
- : WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- : See the License for the specific language governing permissions and
- : limitations under the License.
-:)
-
-import module namespace refl = 'http://www.zorba-xquery.com/modules/reflection';
-import module namespace sctx = "http://www.zorba-xquery.com/modules/introspection/sctx";
-import module namespace base64 = "http://www.zorba-xquery.com/modules/converters/base64";
-
-
-declare variable $local:localns as xs:string := 'http://www.w3.org/2005/xquery-local-functions';
-
-
-declare variable $local:endl as xs:string := '
-';
-
-declare function local:has-to-stop($resp as element())
-{
- fn:not(($resp/@command/data(.) eq "stop" and $resp/@reason/data(.) eq "ok")
- or ($resp/@status/data(.) eq "stopped")
- or ($resp/@status/data(.) eq "stopping"))
-};
-
-declare function local:status($resp as element())
-{
- fn:concat(
- "Status: ", $resp/@status/data(.), $local:endl,
- "Reason: ", $resp/@reason/data(.), $local:endl,
- let $msg := $resp/text()
- return
- if (fn:empty($msg) or $msg eq "") then
- ""
- else
- fn:concat($msg, $local:endl)
- )
-};
-
-
-declare function local:run($resp as element()) {
- if ($resp/@status/data(.) eq "starting") then
- "Starting query"
- else
- local:status($resp)
-};
-
-declare function local:stop($resp as element())
-{
- local:status($resp)
-};
-
-declare function local:breakpoint_set($resp as element())
-{
- if ($resp/error) then
- fn:concat("Error when setting a breakpoint: ", if ($resp/error/message) then $resp/error/message/text() else concat(" errcode: ", data($resp/error/@code)))
- else
- fn:concat("set breakpoint with id ", data($resp/@id), " and state ", data($resp/@state))
-};
-
-declare function local:breakpoint_list($resp as element())
-{
- string-join(
- for $b in $resp/breakpoint
- return concat("Breakpoint ", data($b/@id), " at ", data($b/@filename), ":", data($b/@lineno), " ", data($b/@state)),
- $local:endl
- )
-};
-
-declare function local:breakpoint_remove($resp as element())
-{
- "Breakpoint removed"
-};
-
-declare function local:stack_depth($resp as element())
-{
- concat("Depth: ", data($resp/@depth))
-};
-
-declare function local:stack_get($resp as element())
-{
- string-join(
- for $s in $resp/stack
- return concat("Level ", data($s/@level), " at ", data($s/@filename), ":", data($s/@lineno)),
- $local:endl
- )
-};
-
-
-declare function local:context_names($resp as element())
-{
- string-join(
- for $c in $resp/context
- return concat("Context: ", data($c/@name), " id: ", data($c/@id)),
- $local:endl
- )
-};
-
-declare function local:context_get($resp as element())
-{
- string-join(
- for $p in $resp/property
- return concat(data($p/@fullname), ": [", data($p/@type), "]",
- if ($p/text() ne "") then concat(": ", base64:decode($p/text())) else ""),
- $local:endl
- )
-};
-
-declare function local:eval($resp as element())
-{
- if (data($resp/@success) eq "1") then
- local:context_get($resp)
- else
- concat("Eval failed", ":", $resp/error/message/text())
-};
-
-declare function local:process-response($resp as element())
-{
- if (data($resp/@command) eq "") then
- (fn:true(), $resp/@transaction_id/data(.), local:status($resp))
- else
- let $fun-cont-name := fn:QName($local:localns, concat("local:", $resp/@command/data(.), "-cont"))
- let $fun-msg-name := fn:QName($local:localns, concat("local:", $resp/@command/data(.)))
- return (
- if (sctx:function-arguments-count($fun-cont-name) = 1) then
- refl:invoke($fun-cont-name, $resp)
- else
- local:has-to-stop($resp),
- $resp/@transaction_id/data(.),
- if (sctx:function-arguments-count($fun-msg-name) = 1) then
- refl:invoke($fun-msg-name, $resp)
- else
- "Recieved a message - command not implemented"
- )
-};
-
-declare function local:process-init($init as element())
-{
- fn:true(),
- 0,
- fn:concat(fn:string-join(
- ('Established connection with', $init/@language/data(.), 'client', $init/@appid/data(.)), ' '), '
-')
-};
-
-declare function local:main($response as element()) {
- let $process-fun as xs:QName := fn:QName($local:localns, concat("local:process-", node-name($response)))
- return
- if (sctx:function-arguments-count($process-fun) = 1) then
- refl:invoke($process-fun, $response)
- else (
- true(),
- ($response/@transaction_id, 0)[1]/data(.),
- "ERROR: Recieved unknown node from client"
- )
-};
=== renamed directory 'bin/debug_client' => 'bin/debugger'
=== renamed file 'bin/debug_client/debug_command.h' => 'bin/debugger/command.h'
--- bin/debug_client/debug_command.h 2011-07-04 08:05:46 +0000
+++ bin/debugger/command.h 2011-12-13 11:51:46 +0000
@@ -14,7 +14,9 @@
* limitations under the License.
*/
#pragma once
-#include <zorba/config.h>
+#ifndef ZORBA_DEBUGGER_COMMAND_H
+#define ZORBA_DEBUGGER_COMMAND_H
+
#include <string>
#include <vector>
#include <iostream>
@@ -23,151 +25,18 @@
#include <sstream>
#include <memory>
#include <typeinfo>
-#include "debug_client/tuple.h"
-
-namespace zorba { namespace debugclient {
+
+#include <zorba/config.h>
+
+#include "command_arg.h"
+#include "tuple.h"
+
+
+namespace zorba { namespace debugger {
class DebugClientParseException : public std::exception {
};
- template<typename Tuple>
- class CommandArg;
-
- template<typename Tuple>
- class CommandArgInstance {
- public:
- virtual int get_index() const = 0;
- virtual const CommandArg<Tuple>* get_arg() const = 0;
- virtual void insertValue(Tuple& t) = 0;
- virtual bool isSet(Tuple& t) const = 0;
- };
-
- template<typename T, int Idx, typename Tuple>
- class TypedCommandArgInstance : public CommandArgInstance<Tuple>
- {
- public:
- TypedCommandArgInstance(T aValue, const CommandArg<Tuple>* aArg)
- : theValue(aValue), theArg(aArg) {}
- virtual int get_index() const { return Idx; }
- virtual const CommandArg<Tuple>* get_arg() const { return theArg; }
- virtual void insertValue(Tuple& t)
- {
- ZORBA_TR1_NS::get<Idx>(t).first = true;
- ZORBA_TR1_NS::get<Idx>(t).second = theValue;
- }
- virtual bool isSet(Tuple& t) const
- {
- return ZORBA_TR1_NS::get<Idx>(t).first;
- }
- private:
- T theValue;
- const CommandArg<Tuple>* theArg;
- };
-
- template<typename Tuple>
- class CommandArgType {
- public:
- virtual CommandArgInstance<Tuple>* parse(const std::string& str,
- const CommandArg<Tuple>* arg) = 0;
- virtual bool isVoid() const = 0;
- virtual bool isSet(Tuple& t) const = 0;
- virtual ~CommandArgType() {}
- };
-
- template<typename T, int Idx, typename Tuple>
- class TypedCommandArgType : public CommandArgType<Tuple> {
- public:
- typedef T Type;
- public: // implementation
- TypedCommandArgType(bool aIsVoid) : theIsVoid(aIsVoid) {}
- TypedCommandArgType(const T& aValue,
- bool aIsVoid)
- : theDefault(aValue), theIsVoid(aIsVoid) {}
- virtual CommandArgInstance<Tuple>* parse(const std::string& str,
- const CommandArg<Tuple>* arg)
- {
- T aValue;
- std::stringstream stream(str);
- stream >> aValue;
- if (stream.fail()) {
- std::cerr << "Could not parse argument of type "
- << typeid(T).name()
- << std::endl;
- return 0;
- }
- return new TypedCommandArgInstance<T, Idx, Tuple>(aValue, arg);
- }
- virtual bool isVoid() const { return theIsVoid; }
- virtual bool isSet(Tuple& t) const
- {
- return ZORBA_TR1_NS::get<Idx>(t).first;
- }
- private:
- TypedCommandArgType<T, Idx, Tuple>() {}
- T theDefault;
- bool theIsVoid;
- };
-
- template<typename Tuple>
- class CommandArg {
- public:
- CommandArg(unsigned aId,
- CommandArgType<Tuple>* aType,
- const std::set<std::string>& aFlags,
- const std::string& aDescription,
- bool aIsRequired)
- : theId(aId),
- theType(aType),
- theFlags(aFlags),
- theDescription(aDescription),
- theIsRequired(aIsRequired)
- {
- }
- ~CommandArg() { delete theType; }
- unsigned get_id() const { return theId; }
- bool canHandle(const std::string& arg) const
- {
- if (theFlags.find(arg) != theFlags.end()) {
- return true;
- }
- return false;
- }
- CommandArgInstance<Tuple>* parse(const std::string& str) const
- {
- return theType->parse(str, this);
- }
- bool isVoid() const {
- return theType->isVoid();
- }
- bool isRequired() const { return theIsRequired; }
- std::string get_name() const {
- return *(theFlags.begin());
- }
- bool isSet(Tuple& t) const
- {
- return theType->isSet(t);
- }
- private:
- unsigned theId;
- CommandArgType<Tuple>* theType;
- std::set<std::string> theFlags;
- std::string theDescription;
- bool theIsRequired;
- };
-}} // end namespace zorba
-
-namespace std {
-
- /**
- * This is a helper split function
- */
- vector<string>& operator<< (vector<string>& vec, const string& str);
-
- set<string>& operator<< (set<string>& vec, const string& str);
-} //end namespace std
-
-namespace zorba { namespace debugclient {
-
template<typename Func, typename Tuple, int CommandIdx>
class CommandInstance
{
@@ -188,8 +57,10 @@
class UntypedCommand {
public:
- virtual std::string get_name() const = 0;
- virtual std::string get_description() const = 0;
+ virtual std::string getName() const = 0;
+ virtual std::set<std::string> getAliases() const = 0;
+ virtual std::string getDescription() const = 0;
+ virtual void printHelp() const = 0;
virtual bool execute(const std::vector<std::string>& args) = 0;
};
@@ -197,77 +68,141 @@
class Command : public UntypedCommand {
public:
Command(const std::string& aName, Func& aFunction, const std::string& aDescription)
- : theName(aName), theFunction(aFunction), theDescription(aDescription) {}
+ : theName(aName), theFunction(aFunction), theDescription(aDescription)
+ {}
+
+ Command(const std::string& aName, const std::set<std::string> aAliases, Func& aFunction, const std::string& aDescription)
+ : theName(aName), theAliases(aAliases), theFunction(aFunction), theDescription(aDescription)
+ {}
+
~Command();
+
public:
- Command& operator() (unsigned aId,
- const std::string& aFlags,
- CommandArgType<Tuple>* aType,
- const std::string& aDescription = "",
- bool isRequired = false);
- virtual std::string get_name() const { return theName; }
- virtual std::string get_description() const { return theDescription; }
+
+ void
+ addArgument(
+ unsigned aId,
+ const std::string& aFlags,
+ CommandArgType<Tuple>* aType,
+ const std::string& aDescription = "",
+ bool isRequired = false);
+
+ static void
+ splitNames(
+ const std::string& names,
+ std::set<std::string>& set);
+
+ virtual std::string
+ getName() const
+ {
+ return theName;
+ }
+
+ virtual std::set<std::string> getAliases() const
+ {
+ return theAliases;
+ }
+
+ virtual std::string
+ getDescription() const
+ {
+ return theDescription;
+ }
+
+ virtual void
+ printHelp() const;
+
virtual bool execute(const std::vector<std::string>& args)
{
CommandInstance<Func, Tuple, CommandIdx> instance(theFunction, theTuple);
- if (instance.parseArguments(args, theArgs))
+ if (instance.parseArguments(args, theArgs)) {
instance.execute();
- else
- return false;
- return true;
+ return true;
+ }
+ return false;
}
private:
std::string theName;
+ std::set<std::string> theAliases;
Func& theFunction;
Tuple theTuple;
std::string theDescription;
- std::map<std::string, CommandArg<Tuple>* > theArgs;
- };
-
- class CommandLine {
- public:
- ~CommandLine();
- public:
- void execute();
- CommandLine& operator<< (UntypedCommand* aCommand);
- private:
- std::map<std::string, UntypedCommand*> theCommands;
- };
-
- template<typename Func, typename Tuple, int CommandIdx>
- Command<Func, Tuple, CommandIdx>::~Command()
- {
- typedef std::map<std::string, CommandArg<Tuple>* > ArgType;
- for (typename ArgType::iterator i = theArgs.begin(); i != theArgs.end(); ++i) {
- delete i->second;
- }
- }
-
-
- template<typename Func, typename Tuple, int CommandIdx>
- Command<Func, Tuple, CommandIdx>&
- Command<Func, Tuple, CommandIdx>::operator() (unsigned aId,
- const std::string& aFlags,
- CommandArgType<Tuple>* aType,
- const std::string& aDescription,
- bool isRequired)
- {
- std::set<std::string> args;
- args << aFlags;
- for (std::set<std::string>::iterator i = args.begin(); i != args.end(); ++i) {
- std::string toAdd = (i->size() == 1) ? "-" + *i : "--" + *i;
- theArgs.insert(std::make_pair(toAdd,
- new CommandArg<Tuple>(aId,
- aType,
- args,
- aDescription,
- isRequired)
- )
- );
- }
- return *this;
- }
-
+ std::map<std::string, CommandArg<Tuple>*> theArgs;
+ };
+
+/*****************************************************************************/
+/*****************************************************************************/
+
+template<typename Func, typename Tuple, int CommandIdx>
+Command<Func, Tuple, CommandIdx>::~Command()
+{
+ typedef std::map<std::string, CommandArg<Tuple>*> ArgType;
+ for (typename ArgType::iterator i = theArgs.begin(); i != theArgs.end(); ++i) {
+ delete i->second;
+ }
+}
+
+template<typename Func, typename Tuple, int CommandIdx>
+void
+Command<Func, Tuple, CommandIdx>::printHelp() const
+{
+ std::cout << "Purpose: " << getDescription() << std::endl;
+
+ typename std::map<std::string, CommandArg<Tuple>*>::const_iterator lIter = theArgs.begin();
+ if (lIter == theArgs.end()) {
+ std::cout << "This command has no arguments." << std::endl;
+ std::cout << std::endl;
+ return;
+ }
+
+ std::cout << "Arguments:" << std::endl << std::endl;
+ for (; lIter != theArgs.end(); ++lIter) {
+ std::cout << " " << lIter->first << "\t" << lIter->second->getDescription() << std::endl;
+ }
+ std::cout << std::endl;
+}
+
+template<typename Func, typename Tuple, int CommandIdx>
+void
+Command<Func, Tuple, CommandIdx>::splitNames(const std::string& aNames, std::set<std::string>& aSet)
+{
+ std::string::size_type before = 0;
+ std::string::size_type pos = aNames.find(" ", 0);
+ while (pos != aNames.npos) {
+ std::string lName = aNames.substr(before, pos);
+ if (lName != "") {
+ aSet.insert(lName);
+ }
+ before = pos + 1;
+ pos = aNames.find(" ", before);
+ }
+ std::string lName = aNames.substr(before);
+ if (lName != "") {
+ aSet.insert(lName);
+ }
+}
+
+template<typename Func, typename Tuple, int CommandIdx>
+void
+Command<Func, Tuple, CommandIdx>::addArgument(
+ unsigned aId,
+ const std::string& aFlags,
+ CommandArgType<Tuple>* aType,
+ const std::string& aDescription,
+ bool isRequired)
+{
+ std::set<std::string> lNames;
+ splitNames(aFlags, lNames);
+
+ for (std::set<std::string>::iterator i = lNames.begin(); i != lNames.end(); ++i) {
+ std::string toAdd = (i->size() == 1) ? "-" + *i : "--" + *i;
+ CommandArg<Tuple>* lArg = new CommandArg<Tuple>(aId, aType, lNames, aDescription, isRequired);
+ theArgs.insert(std::make_pair(toAdd, lArg));
+ }
+}
+
+/*****************************************************************************/
+
template<typename Tuple, typename T, int Idx>
CommandArgType<Tuple>* createArgType(Tuple t)
{
@@ -290,6 +225,16 @@
return new Command<Func, Tuple, CommandIdx>(aName, aFunction, aDescription);
}
+ template<int CommandIdx, typename Tuple, typename Func>
+ Command<Func, Tuple, CommandIdx>* createCommand(Tuple t,
+ const std::string& aName,
+ const std::set<std::string>& aAliases,
+ Func& aFunction,
+ const std::string& aDescription)
+ {
+ return new Command<Func, Tuple, CommandIdx>(aName, aAliases, aFunction, aDescription);
+ }
+
template<typename Func, typename Tuple, int CommandIdx>
bool CommandInstance<Func, Tuple, CommandIdx>::
parseArguments(const std::vector<std::string>& args,
@@ -301,29 +246,34 @@
for (ArgType::size_type i = 1; i < size; ++i) {
typename CArgType::const_iterator pos = aCommandArgs.find(args[i]);
if (pos == aCommandArgs.end()) {
- std::cerr << "Error: Unknown Argument " << args[i] << std::endl;
+ std::cerr << "Error: Unknown option " << args[i] << std::endl;
parseError = true;
return false;
}
const CommandArg<Tuple>& arg = *(pos->second);
- if (!arg.isVoid() && args[++i][0] == '-') {
- std::cerr << "Did not expect parameter for option " << args[i] << std::endl;
- return false;
- }
std::auto_ptr<CommandArgInstance<Tuple> > instance;
if (arg.isVoid()) {
instance.reset(arg.parse("1"));
} else {
+ ++i;
+ if (i >= size) {
+ std::cerr << "Error: Missing value for argument " << args[i - 1] << std::endl;
+ parseError = true;
+ allSet = false;
+ return false;
+ }
instance.reset(arg.parse(args[i]));
}
- instance->insertValue(theTuple);
+ if (instance.get()) {
+ instance->insertValue(theTuple);
+ }
}
bool allSet = true;
for (typename CArgType::const_iterator i = aCommandArgs.begin();
i != aCommandArgs.end(); ++i)
{
if (i->second->isRequired() && !i->second->isSet(theTuple)) {
- std::cerr << "Error: Argument " << i->second->get_name() << " not set" << std::endl;
+ std::cerr << "Error: Argument -" << i->second->getName() << " not set" << std::endl;
allSet = false;
}
}
@@ -336,4 +286,7 @@
theFunction.template handle<CommandIdx>(this->theTuple);
}
-}} // end of namespace zorba::debugclient
+} // namespace zorba
+} // namespace debugger
+
+#endif // ZORBA_DEBUGGER_COMMAND_H
=== added file 'bin/debugger/command_arg.h'
--- bin/debugger/command_arg.h 1970-01-01 00:00:00 +0000
+++ bin/debugger/command_arg.h 2011-12-13 11:51:46 +0000
@@ -0,0 +1,237 @@
+/*
+ * Copyright 2006-2008 The FLWOR Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#pragma once
+#ifndef ZORBA_DEBUGGER_COMMAND_ARG_H
+#define ZORBA_DEBUGGER_COMMAND_ARG_H
+
+#include <string>
+#include <iostream>
+#include <set>
+#include <sstream>
+
+#include "tuple.h"
+
+
+namespace zorba { namespace debugger {
+
+template<typename Tuple>
+class CommandArg;
+
+template<typename Tuple>
+class CommandArgInstance {
+ public:
+ virtual int get_index() const = 0;
+ virtual const CommandArg<Tuple>* get_arg() const = 0;
+ virtual void insertValue(Tuple& t) = 0;
+ virtual bool isSet(Tuple& t) const = 0;
+};
+
+template<typename T, int Idx, typename Tuple>
+class TypedCommandArgInstance : public CommandArgInstance<Tuple>
+{
+ public:
+ TypedCommandArgInstance(T aValue, const CommandArg<Tuple>* aArg)
+ : theValue(aValue), theArg(aArg)
+ {
+ }
+
+ virtual int
+ get_index() const
+ {
+ return Idx;
+ }
+
+ virtual const CommandArg<Tuple>*
+ get_arg() const
+ {
+ return theArg;
+ }
+
+ virtual void
+ insertValue(Tuple& t)
+ {
+ ZORBA_TR1_NS::get<Idx>(t).first = true;
+ ZORBA_TR1_NS::get<Idx>(t).second = theValue;
+ }
+
+ virtual bool isSet(Tuple& t) const
+ {
+ return ZORBA_TR1_NS::get<Idx>(t).first;
+ }
+
+ private:
+
+ T theValue;
+ const CommandArg<Tuple>* theArg;
+};
+
+template<typename Tuple>
+class CommandArgType
+{
+ public:
+ virtual CommandArgInstance<Tuple>*
+ parse(
+ const std::string& str,
+ const CommandArg<Tuple>* arg) = 0;
+
+ virtual bool
+ isVoid() const = 0;
+
+ virtual bool
+ isSet(Tuple& t) const = 0;
+
+ virtual ~CommandArgType() {}
+};
+
+ template<typename T, int Idx, typename Tuple>
+ class TypedCommandArgType : public CommandArgType<Tuple> {
+ public:
+ typedef T Type;
+ public: // implementation
+ TypedCommandArgType(bool aIsVoid) : theIsVoid(aIsVoid) {}
+ TypedCommandArgType(const T& aValue,
+ bool aIsVoid)
+ : theDefault(aValue), theIsVoid(aIsVoid) {}
+ virtual CommandArgInstance<Tuple>* parse(const std::string& str,
+ const CommandArg<Tuple>* arg)
+ {
+ T aValue;
+
+ // special treatment for strings
+ // this is a double hack:
+ // - we check the type name if this starts with: class std::basic_string
+ // - we use void* in readEntireString to workaround the template type T
+ // which would otherwise complain during compilation if types and
+ // operators do not match
+ // TOSO: probably someone can find a more elegant solution
+ std::string lTypeName(typeid(T).name());
+ if (lTypeName.find("class std::basic_string") == 0) {
+ readEntireString(str, &aValue);
+ } else {
+ std::stringstream stream(str);
+ std::stringstream out;
+ stream >> aValue;
+ if (stream.fail()) {
+ std::cerr << "Error: Could not parse value \"" << str << "\" as type "
+ << typeid(T).name()
+ << std::endl;
+ return 0;
+ }
+ }
+
+ return new TypedCommandArgInstance<T, Idx, Tuple>(aValue, arg);
+ }
+ virtual bool isVoid() const { return theIsVoid; }
+ virtual bool isSet(Tuple& t) const
+ {
+ return ZORBA_TR1_NS::get<Idx>(t).first;
+ }
+ private:
+ void readEntireString(std::string aIn, void* aValue)
+ {
+ *((std::string*)aValue) = aIn;
+ }
+
+ TypedCommandArgType<T, Idx, Tuple>() {}
+ T theDefault;
+ bool theIsVoid;
+ };
+
+ template<typename Tuple>
+ class CommandArg {
+ public:
+ CommandArg(unsigned aId,
+ CommandArgType<Tuple>* aType,
+ const std::set<std::string>& aNames,
+ const std::string& aDescription,
+ bool aIsRequired)
+ : theId(aId),
+ theType(aType),
+ theNames(aNames),
+ theDescription(aDescription),
+ theIsRequired(aIsRequired)
+ {
+ }
+
+ ~CommandArg()
+ {
+ delete theType;
+ }
+
+ unsigned
+ get_id() const
+ {
+ return theId;
+ }
+
+ bool
+ canHandle(const std::string& arg) const
+ {
+ if (theNames.find(arg) != theNames.end()) {
+ return true;
+ }
+ return false;
+ }
+
+ CommandArgInstance<Tuple>*
+ parse(const std::string& str) const
+ {
+ return theType->parse(str, this);
+ }
+
+ bool
+ isVoid() const
+ {
+ return theType->isVoid();
+ }
+
+ bool
+ isRequired() const
+ {
+ return theIsRequired;
+ }
+
+ std::string
+ getName() const
+ {
+ return *(theNames.begin());
+ }
+
+ std::string
+ getDescription() const
+ {
+ return theDescription;
+ }
+
+ bool
+ isSet(Tuple& t) const
+ {
+ return theType->isSet(t);
+ }
+
+ private:
+
+ unsigned theId;
+ CommandArgType<Tuple>* theType;
+ std::set<std::string> theNames;
+ std::string theDescription;
+ bool theIsRequired;
+ };
+
+} // namespace zorba
+} // namespace debugger
+
+#endif // ZORBA_DEBUGGER_COMMAND_ARG_H
=== modified file 'bin/debugger/command_line_handler.cpp'
--- bin/debug_client/command_line_handler.cpp 2011-07-01 01:53:24 +0000
+++ bin/debugger/command_line_handler.cpp 2011-12-13 11:51:46 +0000
@@ -1,4 +1,4 @@
-/*
+ /*
* Copyright 2006-2008 The FLWOR Foundation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -23,225 +23,372 @@
# define msleep Sleep
#endif
-namespace zorba { namespace debugclient {
+namespace zorba { namespace debugger {
- using namespace ::std;
using namespace ::ZORBA_TR1_NS;
- CommandLineHandler::CommandLineHandler(unsigned short port,
- LockFreeConsumer<std::size_t>& aConsumer,
- LockFreeConsumer<bool>& aContinueQueue,
- EventHandler& aHandler,
- CommandLine& aCommandLine)
+CommandLineHandler::CommandLineHandler(
+ unsigned short port,
+ LockFreeConsumer<std::size_t>& aConsumer,
+ LockFreeConsumer<bool>& aContinueQueue,
+ EventHandler& aHandler,
+ CommandPrompt& aCommandPrompt)
: theConsumer(aConsumer),
theContinueQueue(aContinueQueue),
theClient(DebuggerClient::createDebuggerClient(&aHandler, port, "localhost")),
- theCommandLine(aCommandLine),
- theQuit(false), theContinue(false), theWaitFor(0)
+ theCommandLine(aCommandPrompt),
+ theQuit(false), theTerminated(true), theContinue(false), theWaitFor(0)
{
addCommands();
}
- CommandLineHandler::~CommandLineHandler()
- {
- }
+CommandLineHandler::~CommandLineHandler()
+{
+}
- void CommandLineHandler::execute()
- {
- theClient->accept();
- std::set<std::size_t> lIdList;
- do {
+void
+CommandLineHandler::execute()
+{
+ theClient->accept();
+ std::set<std::size_t> lIdList;
+ do {
+ getNextId(lIdList);
+ while (lIdList.find(theWaitFor) == lIdList.end()) {
getNextId(lIdList);
- while (!theQuit && lIdList.find(theWaitFor) == lIdList.end()) {
- getNextId(lIdList);
- msleep(20);
- }
- while (!theContinueQueue.consume(theQuit)) {
- msleep(20);
- }
- theQuit = !theQuit;
- if (!theQuit) {
- theCommandLine.execute();
- while (theContinue) {
- theContinue = false;
- theCommandLine.execute();
- }
- }
- } while (!theQuit);
- }
-
- void CommandLineHandler::getNextId(std::set<std::size_t>& aIdList)
- {
- std::size_t result;
- if (theConsumer.consume(result)) {
- aIdList.insert(result);
- }
- }
-
- template<>
- void CommandLineHandler::handle<Status>(ZORBA_TR1_NS::tuple<> &t)
- {
- theWaitFor = theClient->status();
- }
-
- template<>
- void CommandLineHandler::handle<Quit>(ZORBA_TR1_NS::tuple<> &t)
- {
+ msleep(20);
+ }
+ bool lCanQuit;
+ while (!theContinueQueue.consume(lCanQuit)) {
+ msleep(20);
+ }
+ if (lCanQuit) {
+ theTerminated = true;
+ }
+ theCommandLine.execute();
+ while (theContinue) {
+ theContinue = false;
+ theCommandLine.execute();
+ }
+ } while (!theQuit);
+}
+
+void
+CommandLineHandler::getNextId(std::set<std::size_t>& aIdList)
+{
+ std::size_t result;
+ if (theConsumer.consume(result)) {
+ aIdList.insert(result);
+ }
+}
+
+template<>
+void
+CommandLineHandler::handle<Status>(ZORBA_TR1_NS::tuple<> &t)
+{
+ theWaitFor = theClient->status();
+}
+
+template<>
+void
+CommandLineHandler::handle<Variables>(ZORBA_TR1_NS::tuple<> &t)
+{
+ theWaitFor = theClient->variables();
+}
+
+template<>
+void
+CommandLineHandler::handle<Quit>(ZORBA_TR1_NS::tuple<> &t)
+{
+ if (!theTerminated) {
bool answered = false;
while (!answered) {
std::cout << "Do you really want to stop debugging and exit? (y/n) ";
- char answer;
- std::cin >> answer;
- std::cout << std::endl;
- if (answer == 'y') {
+ std::string lAnswer;
+ std::getline(std::cin, lAnswer);
+ if (lAnswer == "y" || lAnswer == "yes") {
answered = true;
- } else if (answered == 'n') {
+ } else if (lAnswer == "n" || lAnswer == "no") {
theContinue = true;
return;
}
}
- theWaitFor = theClient->stop();
- theClient->quit();
- }
-
- template<>
- void CommandLineHandler::handle<Run>(ZORBA_TR1_NS::tuple<> &t)
- {
- theWaitFor = theClient->run();
- }
-
- template<>
- void CommandLineHandler::handle<BreakpointSet>(std::tr1::tuple<bstring, bstring, bint> &t)
- {
- DebuggerClient::BreakpointType lType = DebuggerClient::Line;
- bool lEnabled = true;
- if (get<0>(t).first) {
- if (get<0>(t).second == "disabled") {
- lEnabled = false;
- }
- }
- theWaitFor = theClient->breakpoint_set(lType,
- lEnabled,
- get<1>(t).second,
- get<2>(t).second);
- }
-
- template<>
- void CommandLineHandler::handle<BreakpointGet>(tuple<bint> &aTuple)
- {
- theWaitFor = theClient->breakpoint_get(get<0>(aTuple).second);
- }
-
- template<>
- void CommandLineHandler::handle<BreakpointDel>(tuple<bint> &aTuple)
- {
- theWaitFor = theClient->breakpoint_remove(get<0>(aTuple).second);
- }
-
- template<>
- void CommandLineHandler::handle<BreakpointList>(tuple<> &t)
- {
- theWaitFor = theClient->breakpoint_list();
- }
-
- template<>
- void CommandLineHandler::handle<StackDepth>(tuple<> &t)
- {
- theWaitFor = theClient->stack_depth();
- }
-
- template<>
- void CommandLineHandler::handle<StackGet>(tuple<bint> &aTuple)
- {
- if (get<0>(aTuple).first) {
- theWaitFor = theClient->stack_get(get<0>(aTuple).second);
- } else {
- theWaitFor = theClient->stack_get();
- }
- }
-
- template<>
- void CommandLineHandler::handle<ContextNames>(tuple<>& aTuple)
- {
- theWaitFor = theClient->context_names();
- }
-
- template<>
- void CommandLineHandler::handle<ContextGet>(tuple<bint> &aTuple)
- {
- if (get<0>(aTuple).first)
- theWaitFor = theClient->context_get(get<0>(aTuple).second);
- else
- theWaitFor = theClient->context_get();
- }
-
- template<>
- void CommandLineHandler::handle<Eval>(tuple<bstring>& aTuple)
- {
- theWaitFor = theClient->eval(get<0>(aTuple).second);
- }
-
- void CommandLineHandler::addCommands()
- {
- theCommandLine << createCommand<Status>(tuple<>(), "status", *this,
- "Gets the status of the server");
- theCommandLine << createCommand<Quit>(tuple<>(), "quit", *this,
- "Stops debugging and quits the client");
- theCommandLine << createCommand<Run>(tuple<>(), "run", *this, "Run the Query");
- {
- Command<CommandLineHandler, tuple<bstring, bstring, bint>, BreakpointSet>* lCommand =
- createCommand<BreakpointSet>(tuple<bstring, bstring, bint>(), "break", *this, "Set a breakpoint");
- (*lCommand)(0, "s", createArgType<tuple<bstring, bstring, bint>, std::string, 0>(tuple<bstring, bstring, bint>()),
- "breakpoint state (enabled or disabled - default: enabled)", false);
- (*lCommand)(1, "f", createArgType<tuple<bstring, bstring, bint>, std::string, 1>(tuple<bstring, bstring, bint>()),
- "The name of the file where to stop", true);
- (*lCommand)(2, "l", createArgType<tuple<bstring, bstring, bint>, int, 2>(tuple<bstring, bstring, bint>()),
- "The line number", true);
-
- theCommandLine << lCommand;
- }
- {
- Command<CommandLineHandler, tuple<bint>, BreakpointGet>* lCommand
- = createCommand<BreakpointGet>(tuple<bint>(), "binfo", *this,
- "Get information about a given breakpoint");
- (*lCommand)(0, "i", createArgType<tuple<bint>, int, 0>(tuple<bint>()),
- "The id of the breakpoint", true);
-
- theCommandLine << lCommand;
- }
- {
- Command<CommandLineHandler, tuple<bint>, BreakpointDel>* lCommand
- = createCommand<BreakpointDel>(tuple<bint>(), "bdel", *this, "Delete a breakpoint with a given id");
- (*lCommand)(0, "i", createArgType<tuple<bint>, int, 0>(tuple<bint>()), "The id of the breakpoint", true);
-
- theCommandLine << lCommand;
- }
- theCommandLine << createCommand<BreakpointList>(tuple<>(), "blist", *this, "List all set breakpoints");
- theCommandLine << createCommand<StackDepth>(tuple<>(), "sdepth", *this, "Get the depth of the stack");
- {
- Command<CommandLineHandler, tuple<bint>, StackGet>* lCommand
- = createCommand<StackGet>(tuple<bint>(), "sget", *this, "Get information about one or all stack frames");
- (*lCommand)(0, "d", createArgType<tuple<bint>, int, 0>(tuple<bint>()), "The stack entry two show (show all if not provided)", false);
- theCommandLine << lCommand;
- }
- theCommandLine << createCommand<ContextNames>(tuple<>(), "cnames", *this, "Get the names of the avilable contexts");
- {
- Command<CommandLineHandler, tuple<bint>, ContextGet>* lCommand
- = createCommand<ContextGet>(tuple<bint>(), "cget", *this, "Get a context");
-
- (*lCommand)(0, "c", createArgType<tuple<bint>, int, 0>(tuple<bint>()), "The id of the context", false);
-
- theCommandLine << lCommand;
- }
- {
- Command<CommandLineHandler, tuple<bstring>, Eval>* lCommand
- = createCommand<Eval>(tuple<bstring>(), "eval", *this, "Evaluate a function");
-
- (*lCommand)(0, "c", createArgType<tuple<bstring>, std::string, 0>(tuple<bstring>()), "The command to evaluate", true);
-
- theCommandLine << lCommand;
- }
- }
-
-}} // namespace zorba::debugclient
-
+ }
+ theWaitFor = theClient->stop();
+ theClient->quit();
+ theQuit = true;
+}
+
+template<>
+void
+CommandLineHandler::handle<Run>(ZORBA_TR1_NS::tuple<> &t)
+{
+ theTerminated = false;
+ theWaitFor = theClient->run();
+}
+
+template<>
+void
+CommandLineHandler::handle<BreakpointSet>(std::tr1::tuple<bstring, bstring, bint> &aTuple)
+{
+ DebuggerClient::BreakpointType lType = DebuggerClient::Line;
+ bool lEnabled = true;
+ if (get<0>(aTuple).first) {
+ if (get<0>(aTuple).second == "disabled") {
+ lEnabled = false;
+ }
+ }
+ theWaitFor = theClient->breakpoint_set(lType,
+ lEnabled,
+ get<1>(aTuple).second,
+ get<2>(aTuple).second);
+}
+
+template<>
+void
+CommandLineHandler::handle<BreakpointGet>(tuple<bint> &aTuple)
+{
+ theWaitFor = theClient->breakpoint_get(get<0>(aTuple).second);
+}
+
+template<>
+void
+CommandLineHandler::handle<BreakpointRemove>(tuple<bint> &aTuple)
+{
+ theWaitFor = theClient->breakpoint_remove(get<0>(aTuple).second);
+}
+
+template<>
+void
+CommandLineHandler::handle<BreakpointList>(tuple<> &aTuple)
+{
+ theWaitFor = theClient->breakpoint_list();
+}
+
+template<>
+void
+CommandLineHandler::handle<StackDepth>(tuple<> &aTuple)
+{
+ theWaitFor = theClient->stack_depth();
+}
+
+template<>
+void
+CommandLineHandler::handle<StackGet>(tuple<bint> &aTuple)
+{
+ if (get<0>(aTuple).first) {
+ theWaitFor = theClient->stack_get(get<0>(aTuple).second);
+ } else {
+ theWaitFor = theClient->stack_get();
+ }
+}
+
+template<>
+void
+CommandLineHandler::handle<ContextNames>(tuple<>& aTuple)
+{
+ theWaitFor = theClient->context_names();
+}
+
+template<>
+void CommandLineHandler::handle<ContextGet>(tuple<bint, bint> &aTuple)
+{
+ int lDepth = -1;
+ int lContext = -1;
+
+ if (get<0>(aTuple).first) {
+ lDepth = get<0>(aTuple).second;
+ }
+ if (get<1>(aTuple).first) {
+ lContext = get<1>(aTuple).second;
+ }
+ theWaitFor = theClient->context_get(lDepth, lContext);
+}
+
+template<>
+void CommandLineHandler::handle<Source>(tuple<bint, bint, bstring> &aTuple)
+{
+ theWaitFor = theClient->source(
+ get<2>(aTuple).second,
+ get<0>(aTuple).second,
+ get<1>(aTuple).second);
+}
+
+template<>
+void CommandLineHandler::handle<Eval>(tuple<bstring>& aTuple)
+{
+ theWaitFor = theClient->eval(get<0>(aTuple).second);
+}
+
+template<>
+void
+CommandLineHandler::handle<StepIn>(ZORBA_TR1_NS::tuple<> &t)
+{
+ theTerminated = false;
+ theWaitFor = theClient->step_into();
+}
+
+template<>
+void
+CommandLineHandler::handle<StepOut>(ZORBA_TR1_NS::tuple<> &t)
+{
+ theWaitFor = theClient->step_out();
+}
+
+template<>
+void
+CommandLineHandler::handle<StepOver>(ZORBA_TR1_NS::tuple<> &t)
+{
+ theTerminated = false;
+ theWaitFor = theClient->step_over();
+}
+
+void
+CommandLineHandler::addCommands()
+{
+ typedef tuple<> TUPLE;
+ typedef tuple<bint> TUPLE_INT;
+ typedef tuple<bstring> TUPLE_STR;
+ typedef tuple<bint, bint> TUPLE_INT_INT;
+ typedef tuple<bstring, bstring, bint> TUPLE_STR_STR_INT;
+ typedef tuple<bint, bint, bstring> TUPLE_INT_INT_STR;
+
+ // DBGP: status
+ theCommandLine << createCommand<Status>(TUPLE(), "status", *this, "Gets the status of the server");
+
+ // ALIAS: variables (context_get -c -1)
+ {
+ std::set<std::string> lAliases;
+ lAliases.insert("vars");
+ theCommandLine << createCommand<Variables>(TUPLE(), "variables", lAliases, *this, "Gets the variables visible in the current scope");
+ }
+
+ // META: quit
+ theCommandLine << createCommand<Quit>(TUPLE(), "quit", *this, "Stops debugging and quits the client");
+
+ // DBGP: run
+ theCommandLine << createCommand<Run>(TUPLE(), "run", *this, "Run the query");
+
+ // DBGP: breakpoint_set
+ {
+ std::set<std::string> lAliases;
+ lAliases.insert("break");
+ Command<CommandLineHandler, TUPLE_STR_STR_INT, BreakpointSet>* lCommand =
+ createCommand<BreakpointSet>(TUPLE_STR_STR_INT(), "bset", lAliases, *this, "Set a breakpoint");
+
+ lCommand->addArgument(0, "s", createArgType<TUPLE_STR_STR_INT, std::string, 0>(TUPLE_STR_STR_INT()), "breakpoint state (optional, 'enabled' or 'disabled', default: enabled)", false);
+ lCommand->addArgument(1, "f", createArgType<TUPLE_STR_STR_INT, std::string, 1>(TUPLE_STR_STR_INT()), "name of the file where to stop", true);
+ lCommand->addArgument(2, "l", createArgType<TUPLE_STR_STR_INT, int, 2>(TUPLE_STR_STR_INT()), "line number", true);
+
+ theCommandLine << lCommand;
+ }
+
+ // DBGP: breakpoint_get
+ {
+ Command<CommandLineHandler, TUPLE_INT, BreakpointGet>* lCommand =
+ createCommand<BreakpointGet>(TUPLE_INT(), "bget", *this, "Get information about a given breakpoint");
+
+ lCommand->addArgument(0, "d", createArgType<TUPLE_INT, int, 0>(TUPLE_INT()), "breakpoint ID", true);
+
+ theCommandLine << lCommand;
+ }
+
+ // DBGP: breakpoint_remove
+ {
+ std::set<std::string> lAliases;
+ lAliases.insert("clear");
+ lAliases.insert("delete");
+ Command<CommandLineHandler, TUPLE_INT, BreakpointRemove>* lCommand =
+ createCommand<BreakpointRemove>(TUPLE_INT(), "bremove", lAliases, *this, "Delete a breakpoint");
+
+ lCommand->addArgument(0, "d", createArgType<TUPLE_INT, int, 0>(TUPLE_INT()), "breakpoint ID", true);
+
+ theCommandLine << lCommand;
+ }
+
+ // DBGP: breakpoint_list
+ theCommandLine << createCommand<BreakpointList>(TUPLE(), "blist", *this, "List all set breakpoints");
+
+ // DBGP: stack_depth
+ theCommandLine << createCommand<StackDepth>(TUPLE(), "sdepth", *this, "Get the depth of the stack");
+
+ // DBGP: stack_get
+ {
+ Command<CommandLineHandler, TUPLE_INT, StackGet>* lCommand =
+ createCommand<StackGet>(TUPLE_INT(), "sget", *this, "Get information about one or all stack frames");
+
+ lCommand->addArgument(0, "d", createArgType<TUPLE_INT, int, 0>(TUPLE_INT()), "stack frame to show: 0 for current stack frame, N for the main module (optional, all frames are shown if not provided)", false);
+
+ theCommandLine << lCommand;
+ }
+
+ // DBGP: context_names
+ theCommandLine << createCommand<ContextNames>(tuple<>(), "cnames", *this, "Get the names of the avilable contexts");
+ // the DBGP -d arguments for this command is omitted since we always have/return: 0 - Local, 1 - Global
+
+ // DBGP: context_get
+ {
+ Command<CommandLineHandler, TUPLE_INT_INT, ContextGet>* lCommand =
+ createCommand<ContextGet>(TUPLE_INT_INT(), "cget", *this, "Get a context (list variables in this context)");
+
+ lCommand->addArgument(0, "d", createArgType<TUPLE_INT_INT, int, 0>(TUPLE_INT_INT()), "stack depth (optional, default: 0)", false);
+ lCommand->addArgument(0, "c", createArgType<TUPLE_INT_INT, int, 1>(TUPLE_INT_INT()), "context ID: 0 for Local, 1 for Global (optional, default: 0)", false);
+
+ theCommandLine << lCommand;
+ }
+
+ // DBGP: source
+ {
+ std::set<std::string> lAliases;
+ lAliases.insert("list");
+ Command<CommandLineHandler, TUPLE_INT_INT_STR, Source>* lCommand =
+ createCommand<Source>(TUPLE_INT_INT_STR(), "source", lAliases, *this, "List source code");
+
+ lCommand->addArgument(0, "b", createArgType<TUPLE_INT_INT_STR, int, 0>(TUPLE_INT_INT_STR()), "begin line (optional, default: first line)", false);
+ lCommand->addArgument(1, "e", createArgType<TUPLE_INT_INT_STR, int, 1>(TUPLE_INT_INT_STR()), "end line (optional, default: last line)", false);
+ lCommand->addArgument(2, "f", createArgType<TUPLE_INT_INT_STR, std::string, 2>(TUPLE_INT_INT_STR()), "file URI (optional, default: the file in the top-most stack frame during execution, main module otherwise)", false);
+
+ theCommandLine << lCommand;
+ }
+
+ // DBGP: eval
+ {
+ std::set<std::string> lAliases;
+ lAliases.insert("print");
+ Command<CommandLineHandler, TUPLE_STR, Eval>* lCommand =
+ createCommand<Eval>(TUPLE_STR(), "eval", lAliases, *this, "Evaluate an expression");
+
+ // TODO: this argument should not be here at all. Eval has the form: eval -i transaction_id -- {DATA}
+ // Eval should be called with a command like: eval 1 + 3
+ // - no need for an argument name
+ // - everything following the fist contiguous set of whitespaces are sent as string
+ lCommand->addArgument(0, "c", createArgType<TUPLE_STR, std::string, 0>(TUPLE_STR()), "expression to evaluate", true);
+
+ theCommandLine << lCommand;
+ }
+
+ // DBGP: step_in
+ {
+ std::set<std::string> lAliases;
+ lAliases.insert("step");
+ lAliases.insert("s");
+ theCommandLine << createCommand<StepIn>(TUPLE(), "in", lAliases, *this, "Step in");
+ }
+
+ // DBGP: step_out
+ {
+ std::set<std::string> lAliases;
+ lAliases.insert("finish");
+ theCommandLine << createCommand<StepOut>(TUPLE(), "out", lAliases, *this, "Step out");
+ }
+
+ // DBGP: step_over
+ {
+ std::set<std::string> lAliases;
+ lAliases.insert("next");
+ lAliases.insert("n");
+ theCommandLine << createCommand<StepOver>(TUPLE(), "over", lAliases, *this, "Step over");
+ }
+}
+
+} // namespace zorba
+} // namespace debugger
=== modified file 'bin/debugger/command_line_handler.h'
--- bin/debug_client/command_line_handler.h 2011-07-01 01:53:24 +0000
+++ bin/debugger/command_line_handler.h 2011-12-13 11:51:46 +0000
@@ -14,46 +14,69 @@
* limitations under the License.
*/
#pragma once
+#ifndef ZORBA_DEBUGGER_COMMAND_LINE_HANDLER_H
+#define ZORBA_DEBUGGER_COMMAND_LINE_HANDLER_H
#include <set>
#include <cassert>
+
#include <zorba/debugger_client.h>
-#include "debug_command.h"
+
+#include "command.h"
+#include "command_prompt.h"
#include "event_handler.h"
-namespace zorba { namespace debugclient {
-
+
+namespace zorba { namespace debugger {
+
enum Commands {
Status,
+ Variables,
+ Quit,
Run,
BreakpointSet,
BreakpointGet,
- BreakpointDel,
+ BreakpointRemove,
BreakpointList,
StackDepth,
StackGet,
ContextNames,
ContextGet,
+ Source,
Eval,
- Quit
+ StepIn,
+ StepOut,
+ StepOver
};
- class CommandLineHandler {
+class CommandLineHandler
+{
private:
+
typedef std::pair<bool, std::string> bstring;
typedef std::pair<bool, int> bint;
+
public:
- CommandLineHandler(unsigned short port,
- LockFreeConsumer<std::size_t>& aConsumer,
- LockFreeConsumer<bool>& aContinueQueue,
- EventHandler& aHandler,
- CommandLine& aCommandLine);
+
+ CommandLineHandler(
+ unsigned short port,
+ LockFreeConsumer<std::size_t>& aConsumer,
+ LockFreeConsumer<bool>& aContinueQueue,
+ EventHandler& aHandler,
+ CommandPrompt& aCommandPrompt);
+
~CommandLineHandler();
+
public:
void execute();
+
public: // Handlers
+
template<int>
- void handle(ZORBA_TR1_NS::tuple<>& aTuple) { assert(false); }
+ void handle(ZORBA_TR1_NS::tuple<>& aTuple)
+ {
+ assert(false);
+ }
template<int>
void handle(ZORBA_TR1_NS::tuple<bstring, bstring, bint>& t)
@@ -62,63 +85,93 @@
}
template<int>
+ void handle(ZORBA_TR1_NS::tuple<bint, bint, bstring>& t)
+ {
+ assert(false);
+ }
+
+ template<int>
void handle(ZORBA_TR1_NS::tuple<bint>& aTuple)
{
assert(false);
}
template<int>
+ void handle(ZORBA_TR1_NS::tuple<bint, bint>& aTuple)
+ {
+ assert(false);
+ }
+
+ template<int>
void handle(ZORBA_TR1_NS::tuple<bstring>& aTuple)
{
assert(false);
}
+
private:
- LockFreeConsumer<std::size_t>& theConsumer;
- LockFreeConsumer<bool>& theContinueQueue;
- DebuggerClient* theClient;
- CommandLine& theCommandLine;
- bool theQuit;
- bool theContinue;
- std::size_t theWaitFor;
+ LockFreeConsumer<std::size_t>& theConsumer;
+ LockFreeConsumer<bool>& theContinueQueue;
+ DebuggerClient* theClient;
+ CommandPrompt& theCommandLine;
+ bool theQuit;
+ bool theTerminated;
+ bool theContinue;
+ std::size_t theWaitFor;
+
private:
void getNextId(std::set<std::size_t>& aIdList);
void addCommands();
- };
-
- template<>
- void CommandLineHandler::handle<Status> (ZORBA_TR1_NS::tuple<>& t);
-
- template<>
- void CommandLineHandler::handle<Quit> (ZORBA_TR1_NS::tuple<>& t);
-
- template<>
- void CommandLineHandler::handle<Run> (ZORBA_TR1_NS::tuple<> &t);
-
- template<>
- void CommandLineHandler::handle<StackDepth> (ZORBA_TR1_NS::tuple<>& t);
-
- template<>
- void CommandLineHandler::handle<BreakpointList> (ZORBA_TR1_NS::tuple<>& aTuple);
-
- template<>
- void CommandLineHandler::handle<BreakpointSet> (ZORBA_TR1_NS::tuple<bstring, bstring, bint> &t);
-
- template<>
- void CommandLineHandler::handle<BreakpointGet> (ZORBA_TR1_NS::tuple<bint>& aTuple);
-
- template<>
- void CommandLineHandler::handle<BreakpointDel>(ZORBA_TR1_NS::tuple<bint> &aTuple);
-
- template<>
- void CommandLineHandler::handle<StackGet> (ZORBA_TR1_NS::tuple<bint>& aTuple);
-
- template<>
- void CommandLineHandler::handle<ContextNames>(ZORBA_TR1_NS::tuple<> &aTuple);
-
- template<>
- void CommandLineHandler::handle<ContextGet>(ZORBA_TR1_NS::tuple<bint> &aTuple);
-
- template<>
- void CommandLineHandler::handle<Eval>(ZORBA_TR1_NS::tuple<bstring>& aTuple);
-
-}} // close namespaces zorba::debugclient
+};
+
+template<>
+void CommandLineHandler::handle<Status> (ZORBA_TR1_NS::tuple<>& t);
+
+template<>
+void CommandLineHandler::handle<Quit> (ZORBA_TR1_NS::tuple<>& t);
+
+template<>
+void CommandLineHandler::handle<Run> (ZORBA_TR1_NS::tuple<> &t);
+
+template<>
+void CommandLineHandler::handle<StackDepth> (ZORBA_TR1_NS::tuple<>& t);
+
+template<>
+void CommandLineHandler::handle<BreakpointList> (ZORBA_TR1_NS::tuple<>& aTuple);
+
+template<>
+void CommandLineHandler::handle<BreakpointSet> (ZORBA_TR1_NS::tuple<bstring, bstring, bint> &t);
+
+template<>
+void CommandLineHandler::handle<BreakpointGet> (ZORBA_TR1_NS::tuple<bint>& aTuple);
+
+template<>
+void CommandLineHandler::handle<BreakpointRemove>(ZORBA_TR1_NS::tuple<bint> &aTuple);
+
+template<>
+void CommandLineHandler::handle<StackGet> (ZORBA_TR1_NS::tuple<bint>& aTuple);
+
+template<>
+void CommandLineHandler::handle<ContextNames>(ZORBA_TR1_NS::tuple<> &aTuple);
+
+template<>
+void CommandLineHandler::handle<ContextGet>(ZORBA_TR1_NS::tuple<bint, bint> &aTuple);
+
+template<>
+void CommandLineHandler::handle<Source>(ZORBA_TR1_NS::tuple<bint, bint, bstring> &aTuple);
+
+template<>
+void CommandLineHandler::handle<Eval>(ZORBA_TR1_NS::tuple<bstring>& aTuple);
+
+template<>
+void CommandLineHandler::handle<StepIn> (ZORBA_TR1_NS::tuple<> &t);
+
+template<>
+void CommandLineHandler::handle<StepOut> (ZORBA_TR1_NS::tuple<> &t);
+
+template<>
+void CommandLineHandler::handle<StepOver> (ZORBA_TR1_NS::tuple<> &t);
+
+} // namespace zorba
+} // namespace debugger
+
+#endif // ZORBA_DEBUGGER_COMMAND_LINE_HANDLER_H
=== added file 'bin/debugger/command_prompt.cpp'
--- bin/debugger/command_prompt.cpp 1970-01-01 00:00:00 +0000
+++ bin/debugger/command_prompt.cpp 2011-12-13 11:51:46 +0000
@@ -0,0 +1,236 @@
+/*
+ * Copyright 2006-2008 The FLWOR Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include "command_prompt.h"
+
+#include <string>
+#include <vector>
+#include <map>
+#include <iostream>
+
+#include "command.h"
+
+
+namespace zorba { namespace debugger {
+
+CommandPrompt::~CommandPrompt()
+{
+ std::map<std::string, UntypedCommand*>::iterator lIter;
+ for (lIter = theCommands.begin(); lIter != theCommands.end(); ++lIter) {
+ delete lIter->second;
+ }
+}
+
+void
+CommandPrompt::printHelp(UntypedCommand* aCommand)
+{
+ // if no command is provided, print all the available commands
+ if (!aCommand) {
+ std::cout << "Available commands:" << std::endl;
+
+ // print the names of all commands
+ std::map<std::string, UntypedCommand*>::iterator lIter = theCommands.begin();
+ while (lIter != theCommands.end()) {
+ std::cout << " " << (*lIter).first;
+ std::set<std::string> lAliases = (*lIter).second->getAliases();
+ std::set<std::string>::const_iterator lAliasIter = lAliases.begin();
+ while (lAliasIter != lAliases.end()) {
+ std::cout << ", " << *lAliasIter;
+ lAliasIter++;
+ }
+ std::cout << std::endl;
+ lIter++;
+ }
+
+ // some hints for detailed help
+ std::cout << std::endl;
+ std::cout << "Type help <command> to get more information about one command." << std::endl;
+ std::cout << std::endl;
+ } else {
+ // ok, so we have a command; then print the help
+ aCommand->printHelp();
+ }
+}
+
+void
+CommandPrompt::execute()
+{
+ for (;;) {
+ std::cout << "(xqdb) ";
+ std::string lCommandLine;
+ std::getline(std::cin, lCommandLine);
+ std::vector<std::string> lArgs;
+
+ // split the command into arguments
+ parseLine(lCommandLine, lArgs);
+ std::string::size_type lSize = lArgs.size();
+
+ // empty command? do nothing!
+ if (lSize == 0) {
+ lArgs = theLastArgs;
+ if (lArgs.size() == 0) {
+ continue;
+ }
+ }
+ theLastArgs = lArgs;
+
+ UntypedCommand* lCommand = NULL;
+
+ // help is not a command but a hook here
+ if (lArgs.at(0) == "h" || lArgs.at(0) == "help") {
+ std::string lCmd = "";
+
+ // if the user needs the help for a specific command
+ if (lSize > 1) {
+ // do nothing if we don't have a command starting with this prefix?
+ // findCommand will print the appropriate errors
+ if (!findCommand(lArgs[1], lCommand)) {
+ continue;
+ }
+ }
+ printHelp(lCommand);
+ continue;
+ }
+ if (findCommand(lArgs[0], lCommand) && lCommand->execute(lArgs)) {
+ return;
+ }
+ continue;
+ }
+}
+
+CommandPrompt&
+CommandPrompt::operator<<(UntypedCommand *aCommand)
+{
+ theCommands.insert(std::make_pair(aCommand->getName(), aCommand));
+ return *this;
+}
+
+bool
+CommandPrompt::findCommand(const std::string& aPrefix, UntypedCommand*& aCommand)
+{
+ std::vector<UntypedCommand*> lFoundCommands;
+
+ std::map<std::string, UntypedCommand*>::iterator lIter = theCommands.begin();
+ while (lIter != theCommands.end()) {
+ // if a command name is equal with the prefix, this is the command we want
+ if ((*lIter).first == aPrefix) {
+ aCommand = (*lIter).second;
+ return true;
+ }
+
+ bool lIsCandidate = false;
+
+ // add this command to candidate commands if the prefix matches
+ if ((*lIter).first.find(aPrefix) == 0) {
+ lFoundCommands.push_back((*lIter).second);
+ lIsCandidate = true;
+ }
+
+ // now process the aliases
+ std::set<std::string> lAliases = (*lIter).second->getAliases();
+ std::set<std::string>::const_iterator lAliasIter = lAliases.begin();
+ while (lAliasIter != lAliases.end()) {
+ // if a command alias is equal with the prefix, this is the command we want
+ if (*lAliasIter == aPrefix) {
+ aCommand = (*lIter).second;
+ return true;
+ }
+
+ // add this command to candidate commands if the prefix matches one alias
+ // and if the command is not already added
+ if (!lIsCandidate && (*lAliasIter).find(aPrefix) == 0) {
+ lFoundCommands.push_back((*lIter).second);
+ break;
+ }
+ lAliasIter++;
+ }
+
+ lIter++;
+ }
+
+ if (lFoundCommands.empty()) {
+ std::cout << "Command not found: " << aPrefix << std::endl;
+ return false;
+ }
+
+ if (lFoundCommands.size() > 1) {
+ std::cout << "Ambigous command: " << aPrefix << std::endl;
+ // show all possible commands that start with this prefix
+ for (std::string::size_type i = 0; i < lFoundCommands.size(); i++) {
+ UntypedCommand* lCommand = lFoundCommands.at(i);
+
+ // commands
+ if (lCommand->getName().find(aPrefix) == 0) {
+ std::cout << " " << lCommand->getName() << std::endl;
+ }
+
+ // and aliases
+ std::set<std::string> lAliases = lCommand->getAliases();
+ std::set<std::string>::const_iterator lAliasIter = lAliases.begin();
+ while (lAliasIter != lAliases.end()) {
+ if ((*lAliasIter).find(aPrefix) == 0) {
+ std::cout << " " << *lAliasIter << std::endl;
+ }
+ lAliasIter++;
+ }
+ }
+ return false;
+ }
+
+ aCommand = lFoundCommands[0];
+ return true;
+}
+
+void
+CommandPrompt::parseLine(const std::string& aLine, std::vector<std::string>& aVector)
+{
+ std::string::size_type lBefore = 0;
+ std::string::size_type lPos = aLine.find_first_of(" \t", 0);
+
+ while (lPos != aLine.npos) {
+ std::string lSub = aLine.substr(lBefore, lPos - lBefore);
+
+ // if two consecutive spaces, you get an empty string here
+ if (lSub != "") {
+ if (lSub[0] == '"') {
+ std::string::size_type lBeforeCopy = lBefore;
+ do {
+ lBeforeCopy = aLine.find("\"", lBeforeCopy + 1);
+ } while (lPos != aLine.npos && aLine.size() > lPos + 1 && aLine[lPos + 1] == '\\');
+ lPos = lBeforeCopy;
+ lSub = aLine.substr(lBefore + 1, lPos - lBefore - 1);
+ }
+ aVector.push_back(lSub);
+ }
+
+ lBefore = lPos + 1;
+ lPos = aLine.find_first_of(" \t", lBefore);
+ }
+ std::string lSub = aLine.substr(lBefore);
+
+ // catching the case when the command ends with a space
+ if (lSub == "") {
+ return;
+ }
+
+ if (lSub[0] == '"') {
+ lPos = aLine.find("\"", lBefore + 1);
+ lSub = aLine.substr(lBefore + 1, lPos - lBefore - 1);
+ }
+ aVector.push_back(lSub);
+}
+
+} // namespace zorba
+} // namespace debugger
=== added file 'bin/debugger/command_prompt.h'
--- bin/debugger/command_prompt.h 1970-01-01 00:00:00 +0000
+++ bin/debugger/command_prompt.h 2011-12-13 11:51:46 +0000
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2006-2008 The FLWOR Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#pragma once
+#ifndef ZORBA_DEBUGGER_COMMAND_PROMPT_H
+#define ZORBA_DEBUGGER_COMMAND_PROMPT_H
+
+#include <string>
+#include <map>
+#include <vector>
+
+
+namespace zorba { namespace debugger {
+
+class UntypedCommand;
+
+class CommandPrompt
+{
+ public:
+ ~CommandPrompt();
+
+ public:
+
+ void execute();
+
+ CommandPrompt& operator<< (UntypedCommand* command);
+
+ private:
+
+ void
+ printHelp(UntypedCommand* command);
+
+ bool
+ findCommand(const std::string& prefix, UntypedCommand*& command);
+
+ void
+ parseLine(const std::string& line, std::vector<std::string>& vector);
+
+ private:
+ std::map<std::string, UntypedCommand*> theCommands;
+ std::vector<std::string> theLastArgs;
+};
+
+
+} // namespace zorba
+} // namespace debugger
+
+#endif // ZORBA_DEBUGGER_COMMAND_PROMPT_H
=== modified file 'bin/debugger/event_handler.cpp'
--- bin/debug_client/event_handler.cpp 2011-07-01 01:53:24 +0000
+++ bin/debugger/event_handler.cpp 2011-12-13 11:51:46 +0000
@@ -13,88 +13,94 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+
+#include "event_handler.h"
+
+#include <sstream>
+
#include <zorba/zorba.h>
#include <zorba/store_manager.h>
#include <zorba/iterator.h>
-#include <sstream>
-#include "debug_client/event_handler.h"
-namespace zorba { namespace debugclient {
+namespace zorba { namespace debugger {
- EventHandler::EventHandler(LockFreeProducer<std::size_t>& aQueue, LockFreeProducer<bool>& aContProducer)
+EventHandler::EventHandler(LockFreeProducer<std::size_t>& aQueue, LockFreeProducer<bool>& aContProducer)
: theIdQueue(aQueue), theContinueProducer(aContProducer),
theStore(StoreManager::getStore()),
theZorbaInstance(Zorba::getInstance(theStore)),
theStaticContext(theZorbaInstance->createStaticContext())
-
- {
- try {
- Zorba_CompilerHints_t lHints;
- lHints.opt_level = ZORBA_OPT_LEVEL_O1;
- std::auto_ptr<std::istream> stream(getCurrentDirectory());
- zorba::String query;
- char buffer[1024];
- std::string::size_type s;
- while ((s = stream->readsome(buffer, 1024))) {
- query.append(std::string(buffer, s));
- }
- theStaticContext->loadProlog(query, lHints);
- } catch (zorba::ZorbaException& e) {
- std::cerr << "Exception: I was not able to load the query file:" << std::endl;
- std::cerr << e.what() << std::endl;
- throw;
- }
- }
-
- EventHandler::~EventHandler()
- {
- theStaticContext = 0;
- theZorbaInstance->shutdown();
- StoreManager::shutdownStore(theStore);
- }
-
- void EventHandler::parseMessage(const std::string &aMessage)
- {
- try {
- zorba::String queryString = "local:main(";
- queryString += aMessage + ")";
- XQuery_t query = theZorbaInstance->compileQuery(queryString, theStaticContext);
- Iterator_t lIter = query->iterator();
- Item item;
- lIter->open();
- bool doContinue = false;
- lIter->next(item);
- {
- const std::string& continueString = item.getStringValue().str();
- if (continueString == "true") {
- doContinue = true;
- } else if (continueString == "false") {
- doContinue = false;
- } else {
- std::stringstream stream(continueString);
- stream >> doContinue;
- }
- }
- lIter->next(item);
- std::size_t lId;
- {
- std::stringstream stream(item.getStringValue().c_str());
- stream >> lId;
- }
- lIter->next(item);
- std::cout << item.getStringValue() << std::endl;
- theContinueProducer.produce(doContinue);
- theIdQueue.produce(lId);
- } catch (ZorbaException& e) {
- std::cerr << "FATAL: could not execute query: " << std::endl;
- std::cerr << e << std::endl;
- std::cerr << "This is a bug, please report to zorba-users@xxxxxxxxxxxxxxxxxxxxx" << std::endl;
- theContinueProducer.produce(false);
- }
- }
-
- void EventHandler::error(unsigned int errcode, const std::string &msg)
- {
- std::cerr << "Error " << errcode << ": " << msg << std::endl;
- }
-}}
+{
+}
+
+EventHandler::~EventHandler()
+{
+ theStaticContext = 0;
+ theZorbaInstance->shutdown();
+ StoreManager::shutdownStore(theStore);
+}
+
+void
+EventHandler::init()
+{
+ try {
+ Zorba_CompilerHints_t lHints;
+ lHints.opt_level = ZORBA_OPT_LEVEL_O1;
+ zorba::String lProlog("import module namespace dmh = 'http://www.zorba-xquery.com/modules/debugger/dbgp-message-handler';");
+ theStaticContext->loadProlog(lProlog, lHints);
+ } catch (zorba::ZorbaException& e) {
+ std::cerr << "Exception: I was not able to load the query file:" << std::endl;
+ std::cerr << e.what() << std::endl;
+ throw;
+ }
+}
+
+void
+EventHandler::parseMessage(const std::string &aMessage)
+{
+ try {
+#ifndef NDEBUG
+ // uncomment this to see the raw messages received by the event handler
+ //std::cout << "Processing response: " << aMessage << std::endl;
+#endif
+ // the query to process the response
+ std::stringstream lQueryStream;
+ lQueryStream << "dmh:process(" << aMessage << ")";
+ XQuery_t lQuery = theZorbaInstance->compileQuery(lQueryStream.str(), theStaticContext);
+
+ // get the query result sequrence:
+ // 1. a message
+ Iterator_t lIter = lQuery->iterator();
+ Item lItem;
+ lIter->open();
+ lIter->next(lItem);
+ std::size_t lId;
+ std::stringstream lStream(lItem.getStringValue().c_str());
+ lStream >> lId;
+
+ // 2. an "idle" flag (to disable quit confirmation)
+ bool lCanQuit = false;
+ if (lIter->next(lItem)) {
+ String lMessage = lItem.getStringValue();
+ lCanQuit = lMessage == "idle";
+ std::cout << std::endl << lItem.getStringValue() << std::endl;
+ }
+ theContinueProducer.produce(lCanQuit);
+
+ // go and solve the event with this id
+ theIdQueue.produce(lId);
+ } catch (ZorbaException& e) {
+ std::cerr << "FATAL: could not execute query: " << std::endl;
+ std::cerr << e << std::endl;
+ std::cerr << "This is a bug, please report to zorba-users@xxxxxxxxxxxxxxxxxxxxx" << std::endl;
+ //theContinueProducer.produce(false);
+ }
+}
+
+void
+EventHandler::error(unsigned int errcode, const std::string &msg)
+{
+ std::cerr << "Error " << errcode << ": " << msg << std::endl;
+}
+
+} // namespace zorba
+} // namespace debugger
=== modified file 'bin/debugger/event_handler.h'
--- bin/debug_client/event_handler.h 2011-07-01 01:53:24 +0000
+++ bin/debugger/event_handler.h 2011-12-13 11:51:46 +0000
@@ -14,33 +14,46 @@
* limitations under the License.
*/
#pragma once
+#ifndef ZORBA_DEBUGGER_EVENT_HANDLER_H
+#define ZORBA_DEBUGGER_EVENT_HANDLER_H
+
#include <string>
#include <iostream>
+
#include <zorba/debugger_event_handler.h>
#include <zorba/static_context.h>
+
#include "lock_free_queue.h"
-namespace zorba {
- class Zorba;
-}
-
-namespace zorba { namespace debugclient {
-
- class EventHandler : public zorba::DebuggerEventHandler
- {
+
+namespace zorba { namespace debugger {
+
+class EventHandler : public zorba::DebuggerEventHandler
+{
public:
- EventHandler(LockFreeProducer<std::size_t>& aQueue, LockFreeProducer<bool>& aContQueue);
+ EventHandler(
+ LockFreeProducer<std::size_t>& aQueue,
+ LockFreeProducer<bool>& aContQueue);
+
~EventHandler();
+
public:
virtual void parseMessage(const std::string& aMessage);
+
virtual void error(unsigned int errcode, const std::string& msg);
+
+ virtual void init();
+
private:
- static std::istream* getCurrentDirectory();
LockFreeProducer<std::size_t>& theIdQueue;
LockFreeProducer<bool>& theContinueProducer;
void* theStore;
Zorba* theZorbaInstance;
StaticContext_t theStaticContext;
- };
+
+};
-}} // end of namespace zorba::debugclient
+} // namespace zorba
+} // namespace debugger
+
+#endif // ZORBA_DEBUGGER_EVENT_HANDLER_H
=== modified file 'bin/debugger/lock_free_queue.h'
--- bin/debug_client/lock_free_queue.h 2011-07-01 01:53:24 +0000
+++ bin/debugger/lock_free_queue.h 2011-12-13 11:51:46 +0000
@@ -14,10 +14,14 @@
* limitations under the License.
*/
#pragma once
+#ifndef ZORBA_DEBUGGER_LOCK_FREE_QUEUE_H
+#define ZORBA_DEBUGGER_LOCK_FREE_QUEUE_H
+
#include <iostream>
#include <list>
-namespace zorba { namespace debugclient {
+
+namespace zorba { namespace debugger {
template<typename T>
class LockFreeProducer
@@ -80,4 +84,8 @@
}
return false;
}
-}} // namespace zorba::debugclient
+
+} // namespace zorba
+} // namespace debugger
+
+#endif // ZORBA_DEBUGGER_LOCK_FREE_QUEUE_H
=== modified file 'bin/debugger/main.cpp'
--- bin/debug_client/main.cpp 2011-07-01 01:53:24 +0000
+++ bin/debugger/main.cpp 2011-12-13 11:51:46 +0000
@@ -13,12 +13,244 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+
+#ifdef WIN32
+# include <windows.h>
+# include <string.h>
+# include <strsafe.h>
+#endif
+
+#include <vector>
+
#include <zorba/config.h>
-#include "debug_command.h"
+
+#include "command_prompt.h"
#include "command_line_handler.h"
using namespace zorba;
-using namespace zorba::debugclient;
+using namespace zorba::debugger;
+
+int
+startZorba(std::string& aExec, std::vector<std::string>& aArgs)
+{
+#ifdef WIN32
+ // **************************
+ // start a process on Windows
+
+ DWORD iReturnVal = 0;
+ DWORD dwExitCode = 0;
+
+ std::wstring lExec;
+ std::wstring lArgs;
+
+ lExec.assign(aExec.begin(), aExec.end());
+
+ // the executable must be the first in the list of arguments
+ lArgs.append(L"\"");
+ lArgs.append(lExec);
+ lArgs.append(L"\"");
+
+ for (std::vector<std::string>::size_type j = 0; j < aArgs.size(); j++) {
+ std::string lArg(aArgs.at(j));
+ std::wstring lArgW;
+ lArgW.assign(lArg.begin(), lArg.end());
+ lArgs.append(L" ");
+ lArgs.append(lArgW);
+ }
+
+ // CreateProcessW can modify Parameters thus we allocate needed memory
+ wchar_t * pwszParam = new wchar_t[lArgs.size() + 1];
+ if (pwszParam == 0) {
+ return 1;
+ }
+ const wchar_t* pchrTemp = lArgs.c_str();
+ wcscpy_s(pwszParam, lArgs.size() + 1, pchrTemp);
+
+ // CreateProcess API initialization
+ STARTUPINFOW siStartupInfo;
+ PROCESS_INFORMATION piProcessInfo;
+ memset(&siStartupInfo, 0, sizeof(siStartupInfo));
+ memset(&piProcessInfo, 0, sizeof(piProcessInfo));
+ siStartupInfo.cb = sizeof(siStartupInfo);
+
+ BOOL lResult = CreateProcessW(
+ const_cast<LPCWSTR>(lExec.c_str()),
+ pwszParam, 0, 0, false,
+ CREATE_DEFAULT_ERROR_MODE, 0, 0,
+ &siStartupInfo, &piProcessInfo);
+
+ if (lResult) {
+ // Watch the process
+ dwExitCode = WaitForSingleObject(piProcessInfo.hProcess, 0);
+ }
+ else {
+ // CreateProcess failed
+ iReturnVal = GetLastError();
+ LPVOID lpMsgBuf;
+ LPVOID lpDisplayBuf;
+
+ FormatMessage(
+ FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
+ NULL,
+ iReturnVal,
+ MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
+ (LPTSTR) &lpMsgBuf,
+ 0, NULL);
+
+ // Display the error message and exit the process
+
+ lpDisplayBuf = (LPVOID)LocalAlloc(
+ LMEM_ZEROINIT,
+ (lstrlen((LPCTSTR)lpMsgBuf) + 40) * sizeof(TCHAR));
+
+ StringCchPrintf(
+ (LPTSTR)lpDisplayBuf,
+ LocalSize(lpDisplayBuf) / sizeof(TCHAR),
+ TEXT("Error (%d) when starting zorba: %s"),
+ iReturnVal,
+ lpMsgBuf);
+
+ std::wstring lErrorW((wchar_t*)lpDisplayBuf);
+ std::string lError;
+ lError.assign(lErrorW.begin(), lErrorW.end());
+ std::cout << lError << std::endl;
+
+ LocalFree(lpMsgBuf);
+ LocalFree(lpDisplayBuf);
+ }
+
+ // Free memory
+ delete[]pwszParam;
+ pwszParam = 0;
+
+ // Release handles
+ CloseHandle(piProcessInfo.hProcess);
+ CloseHandle(piProcessInfo.hThread);
+
+ return iReturnVal;
+
+#else
+ // ************************
+ // start a process on Linux
+
+ pid_t pID = fork();
+ if (pID == 0) {
+ // Code only executed by child process
+ std::stringstream lCommand;
+ lCommand << aExec;
+ for (std::vector<std::string>::size_type j = 0; j < aArgs.size(); j++) {
+ lCommand << " " << aArgs.at(j);
+ }
+
+ int lRes = system(lCommand.str().c_str());
+ exit(lRes);
+ }
+ else {
+ // Code only executed by parent process
+ if (pID < 0) {
+ std::cerr << "Failed to fork Zorba" << std::endl;
+ return pID;
+ } else {
+ return 0;
+ }
+ }
+#endif
+}
+
+void printUsage(std::string& aProgram)
+{
+ std::cerr << "Usage:" << std::endl
+ << " " << aProgram << " <zorba_arguments>" << std::endl
+ << " this will start a debugger command line and a zorba process with the given arguments" << std::endl;
+}
+
+bool
+processArguments(
+ int argc,
+ char* argv[],
+ std::string& aProgram,
+ bool& aStandalone,
+ std::string& aZorba,
+ unsigned int& aPort,
+ std::vector<std::string>& aZorbaArgs)
+{
+ aPort = 28028;
+
+ // find the path to Zorba and this executable name
+ aProgram = argv[0];
+
+#ifdef WIN32
+ char lSep = '\\';
+#else
+ char lSep = '/';
+#endif
+ std::string::size_type lPos = aProgram.find_last_of(lSep);
+
+ std::stringstream lZs;
+
+ if (lPos == aProgram.npos) {
+ lZs << "." << lSep;
+ } else {
+ lZs << aProgram.substr(0, lPos + 1);
+ aProgram = aProgram.substr(lPos + 1);
+ }
+ lZs << "zorba";
+#ifdef WIN32
+ lZs << ".exe";
+#endif
+ aZorba = lZs.str();
+
+
+ bool lHasFileArg = false;
+ bool lHasQueryArg = false;
+ bool lHasQueryVal = false;
+
+ // find if the user asked for help or specified a specific port
+ for (int i = 1; i < argc; i++) {
+ std::string lArg = argv[i];
+ if (lArg == "-h" || lArg == "--help") {
+ return false;
+ }
+ else if (lArg == "-p" || lArg == "--debug-port") {
+ // if there is one more argument
+ if (i < argc - 1) {
+ // get the port value
+ int lPort;
+ std::stringstream lStream(argv[i + 1]);
+ lStream >> lPort;
+ if (!lStream.fail()) {
+ aPort = lPort;
+ }
+ }
+ }
+ else if (lArg == "-f") {
+ lHasFileArg = true;
+ }
+ else if (lArg == "-q") {
+ lHasQueryArg = true;
+ if (++i < argc) {
+ lHasQueryVal = true;
+ }
+ }
+ }
+
+ if (!lHasFileArg || !lHasQueryArg || !lHasQueryVal) {
+ std::cout << "Not enough arguments to start Zorba." << std::endl;
+ std::cout << "Running the standalone XQuery debugger client on port: " << aPort << std::endl;
+ return true;
+ }
+
+ // zorba will need the -d flag
+ aZorbaArgs.push_back("-d");
+
+ // gather all arguments (excepting the program name)
+ for (int i = 1; i < argc; i++) {
+ aZorbaArgs.push_back(argv[i]);
+ }
+
+ aStandalone = false;
+ return true;
+}
#ifndef _WIN32_WCE
int
@@ -28,24 +260,68 @@
_tmain(int argc, _TCHAR* argv[])
#endif
{
- int port = 28028;
- if (argv[1]) {
- std::stringstream stream(argv[1]);
- stream >> port;
- if (stream.fail() || argv[2]) {
- std::cerr << "Unknown argument. USAGE: " << argv[0] << " [PORT]" << std::endl;
- return 2;
+ // **************************************************************************
+ // processing arguments
+
+ std::string lProgram, lZorbaExec;
+ unsigned int lPort = 28028;
+ std::vector<std::string> lZorbaArgs;
+
+ bool lStandalone = true;
+ if (!processArguments(argc, argv, lProgram, lStandalone, lZorbaExec, lPort, lZorbaArgs)) {
+ printUsage(lProgram);
+ return 1;
+ }
+
+#ifndef NDEBUG
+ // **************************************************************************
+ // debug reporting
+
+ if (!lStandalone) {
+ std::cout << "Communication port: " << lPort << std::endl;
+ std::cout << "Zorba executable: " << lZorbaExec << std::endl;
+ std::cout << "Zorba arguments: ";
+ for (std::vector<std::string>::size_type j = 0; j < lZorbaArgs.size(); j++) {
+ std::cout << lZorbaArgs.at(j) << " ";
}
+ std::cout << std::endl;
}
+#endif
+
try {
+ // **************************************************************************
+ // start a zorba
+
+ if (!lStandalone) {
+ int lResult = startZorba(lZorbaExec, lZorbaArgs);
+ if (lResult) {
+ return lResult;
+ }
+ } else {
+ std::cout << "Waiting for an incomming Zorba connection..." << std::endl;
+ }
+
+ // **************************************************************************
+ // start the debugger command line
+
LockFreeQueue<std::size_t> lQueue;
LockFreeQueue<bool> lContEvent;
- EventHandler lHandler(lQueue, lContEvent);
- CommandLine cli;
- CommandLineHandler handler(port, lQueue, lContEvent, lHandler, cli);
- handler.execute();
+ EventHandler lEventHandler(lQueue, lContEvent);
+ lEventHandler.init();
+
+ CommandPrompt lCommandPrompt;
+ CommandLineHandler lCommandLineHandler(lPort, lQueue, lContEvent, lEventHandler, lCommandPrompt);
+
+ lCommandLineHandler.execute();
+
+#ifndef WIN32
+ wait();
+#endif
+
} catch (...) {
- return 4;
+ return -1;
}
+
return 0;
}
+
=== modified file 'bin/debugger/tuple.h'
--- bin/debug_client/tuple.h 2011-07-04 08:05:46 +0000
+++ bin/debugger/tuple.h 2011-12-13 11:51:46 +0000
@@ -14,9 +14,15 @@
* limitations under the License.
*/
#pragma once
+#ifndef ZORBA_DEBUGGER_TUPLE_H
+#define ZORBA_DEBUGGER_TUPLE_H
+
#include <zorba/config.h>
+
#if ZORBA_TR1_IN_TR1_SUBDIRECTORY
# include <tr1/tuple>
#else
# include <tuple>
#endif
+
+#endif // ZORBA_DEBUGGER_TUPLE_H
=== modified file 'bin/zorbacmd.cpp'
--- bin/zorbacmd.cpp 2011-11-08 03:11:02 +0000
+++ bin/zorbacmd.cpp 2011-12-13 11:51:46 +0000
@@ -925,17 +925,15 @@
lHost = "127.0.0.1";
}
- if (lProperties.debug()) {
- Zorba_SerializerOptions lSerOptions =
- Zorba_SerializerOptions::SerializerOptionsFromStringParams(
- lProperties.getSerializerParameters());
- createSerializerOptions(lSerOptions, lProperties);
+ Zorba_SerializerOptions lSerOptions =
+ Zorba_SerializerOptions::SerializerOptionsFromStringParams(
+ lProperties.getSerializerParameters());
+ createSerializerOptions(lSerOptions, lProperties);
- if (!lProperties.hasNoLogo() && !lProperties.debug()) {
- std::cout << "Zorba XQuery Debugger Server\n" << copyright_str << std::endl;
- }
- lQuery->debug(*lOutputStream, lSerOptions, lHost, lProperties.getDebugPort());
+ if (!lProperties.hasNoLogo()) {
+ std::cout << "Zorba XQuery Debugger Server\n" << copyright_str << std::endl;
}
+ lQuery->debug(*lOutputStream, lSerOptions, lHost, lProperties.getDebugPort());
}
catch (zorba::XQueryException const& qe)
{
=== modified file 'include/zorba/debugger_client.h'
--- include/zorba/debugger_client.h 2011-07-24 22:28:31 +0000
+++ include/zorba/debugger_client.h 2011-12-13 11:51:46 +0000
@@ -162,6 +162,13 @@
* @return The id of the request.
*/
virtual std::size_t status() = 0;
+
+ /**
+ * @brief Get the variables in all the contexts in the topmost stack frame.
+ *
+ * @return The id of the request.
+ */
+ virtual std::size_t variables() = 0;
/**
* @brief Query the debug engine for supported features.
@@ -521,6 +528,7 @@
*/
virtual void quit() = 0;
};
+
}//end of namespace
+
#endif
-/* vim:set et sw=2 ts=2: */
=== modified file 'modules/com/zorba-xquery/www/modules/CMakeLists.txt'
--- modules/com/zorba-xquery/www/modules/CMakeLists.txt 2011-10-14 07:35:51 +0000
+++ modules/com/zorba-xquery/www/modules/CMakeLists.txt 2011-12-13 11:51:46 +0000
@@ -100,6 +100,13 @@
DECLARE_ZORBA_MODULE(FILE store/static/integrity_constraints/dml.xq VERSION 2.0
URI "http://www.zorba-xquery.com/modules/store/static/integrity_constraints/dml")
+# debugger client DBGP message handler module
+IF (ZORBA_WITH_DEBUGGER)
+ DECLARE_ZORBA_MODULE (FILE debugger/dbgp-message-handler.xq VERSION 1.0
+ URI "http://www.zorba-xquery.com/modules/debugger/dbgp-message-handler")
+ENDIF (ZORBA_WITH_DEBUGGER)
+
+
# error and warning modules
DECLARE_ZORBA_MODULE (FILE pregenerated/errors.xq
URI "http://www.zorba-xquery.com/errors"
=== added directory 'modules/com/zorba-xquery/www/modules/debugger'
=== added file 'modules/com/zorba-xquery/www/modules/debugger/dbgp-message-handler.xq'
--- modules/com/zorba-xquery/www/modules/debugger/dbgp-message-handler.xq 1970-01-01 00:00:00 +0000
+++ modules/com/zorba-xquery/www/modules/debugger/dbgp-message-handler.xq 2011-12-13 11:51:46 +0000
@@ -0,0 +1,272 @@
+(:
+ : Copyright 2006-2009 The FLWOR Foundation.
+ :
+ : Licensed under the Apache License, Version 2.0 (the "License");
+ : you may not use this file except in compliance with the License.
+ : You may obtain a copy of the License at
+ :
+ : http://www.apache.org/licenses/LICENSE-2.0
+ :
+ : Unless required by applicable law or agreed to in writing, software
+ : distributed under the License is distributed on an "AS IS" BASIS,
+ : WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ : See the License for the specific language governing permissions and
+ : limitations under the License.
+:)
+module namespace dmh = "http://www.zorba-xquery.com/modules/debugger/dbgp-message-handler";
+
+import module namespace base64 = "http://www.zorba-xquery.com/modules/converters/base64";
+
+
+declare variable $dmh:endl as xs:string := "
+";
+
+(:~
+ : Set this variale to true if you want to have mode debug information when
+ : an error occurs.
+ :)
+declare variable $dmh:debug as xs:boolean := fn:false();
+
+
+declare %private function dmh:status($resp as element(response))
+{
+ switch ($resp/@status)
+ case "starting"
+ case "stopping"
+ return "idle"
+ case "break"
+ return
+ let $status := $resp/@status
+ let $whyInfo :=
+ if ($resp/@reason ne "ok") then
+ fn:concat(" (", $resp/@reason, ")")
+ else
+ ""
+ let $whereInfo :=
+ if ($resp/text()[1] ne "") then
+ fn:concat(" in ", $resp/text()[1])
+ else
+ ""
+ return
+ fn:concat($status, $whyInfo, $whereInfo)
+ default
+ return $resp/@status
+};
+
+declare %private function dmh:source($resp as element(response))
+{
+ $resp/text()
+};
+
+declare %private function dmh:breakpoint-set($resp as element(response))
+{
+ fn:concat("set breakpoint with id ", data($resp/@id), " and state ", data($resp/@state))
+};
+
+declare %private function dmh:breakpoint-get($resp as element(response))
+{
+ let $b := $resp/breakpoint
+ return
+ fn:concat(
+ "Breakpoint ", $b/@id, $dmh:endl,
+ " type: ", $b/@type, $dmh:endl,
+ " file: ", $b/@filename, $dmh:endl,
+ " line: ", $b/@lineno, $dmh:endl,
+ " state: ", $b/@state
+ )
+};
+
+declare %private function dmh:breakpoint-list($resp as element(response))
+{
+ fn:string-join(
+ let $bs := $resp/breakpoint
+ return
+ if (fn:exists($bs)) then
+ fn:concat(
+ "--------------------------------------", $dmh:endl,
+ "| ID | State | Line | File", $dmh:endl,
+ "|--------|-----------|--------|-------", $dmh:endl,
+ fn:string-join(
+ for $b in $bs
+ return
+ fn:concat(
+ "| ", dmh:lpottl($b/@id, 6, " "), " ",
+ "| ", if ($b/@state eq "enabled") then "enabled " else "disabled ", " ",
+ "| ", dmh:lpottl($b/@lineno, 6, " "), " ",
+ "| ", $b/@filename, $dmh:endl),
+ ""
+ ),
+ "--------------------------------------", $dmh:endl
+ )
+ else
+ "No breakpoints set"
+ )
+};
+
+(:~
+ : left-pad-or-trim-to-length
+ :)
+declare %private function dmh:lpottl($value as xs:string, $length as xs:integer, $padChar as xs:string)
+ as xs:string
+{
+ let $padChar := fn:substring($padChar, 1, 1)
+ let $len := fn:string-length($value)
+ return
+ if ($len < $length) then
+ let $pad :=
+ fn:string-join(
+ for $i in 1 to $length - $len
+ return $padChar,
+ ""
+ )
+ return
+ fn:concat($pad, $value)
+ else
+ fn:substring($value, $len - $length + 1)
+};
+
+declare %private function dmh:breakpoint-remove($resp as element(response))
+{
+ "Breakpoint removed"
+};
+
+declare %private function dmh:stack-depth($resp as element(response))
+{
+ fn:concat("depth: ", $resp/@depth)
+};
+
+declare %private function dmh:stack-get($resp as element(response))
+{
+ fn:string-join(
+ for $s in $resp/stack
+ return
+ fn:concat("#", $s/@level, " in ", $s/@where, " at ", $s/@filename, ":", $s/@lineno),
+ $dmh:endl
+ )
+};
+
+
+declare %private function dmh:context-names($resp as element(response))
+{
+ fn:string-join(
+ for $c in $resp/context
+ return
+ fn:concat("context ", $c/@id, ": ", $c/@name),
+ $dmh:endl
+ )
+};
+
+declare %private function dmh:context-get($resp as element(response))
+{
+ fn:string-join(
+ for $p in $resp/property
+ return
+ fn:concat($p/@fullname, " ", $p/@type,
+ if ($p/text() ne "") then
+ fn:concat(": ", base64:decode($p/text()))
+ else
+ ""
+ ),
+ $dmh:endl
+ )
+};
+
+declare %private function dmh:eval($resp as element(response))
+{
+ if ($resp/@success eq "1") then
+ dmh:context-get($resp)
+ else
+ dmh:report-error("An unknown error occured while evaluating expression.")
+};
+
+declare %private function dmh:report-error(
+ $message as xs:string)
+{
+ dmh:report-error($message, ())
+};
+
+declare %private function dmh:report-error(
+ $message as xs:string,
+ $debugMessage as xs:string*)
+{
+ fn:string-join(
+ (
+ (: the error message :)
+ fn:concat("Error: ", $message),
+
+ (: the debug info :)
+ if ($dmh:debug and fn:string-length($debugMessage) gt 0) then
+ $debugMessage
+ else
+ ()
+ ),
+ $dmh:endl
+ )
+};
+
+declare %private function dmh:process-response($resp as element(response))
+{
+ switch ($resp/@command)
+ case "eval" return dmh:eval($resp)
+ case "context_get" return dmh:context-get($resp)
+ case "context_names" return dmh:context-names($resp)
+ case "stack_get" return dmh:stack-get($resp)
+ case "stack_depth" return dmh:stack-depth($resp)
+ case "breakpoint_remove" return dmh:breakpoint-remove($resp)
+ case "breakpoint_list" return dmh:breakpoint-list($resp)
+ case "breakpoint_get" return dmh:breakpoint-get($resp)
+ case "breakpoint_set" return dmh:breakpoint-set($resp)
+ case "source" return dmh:source($resp)
+
+ (: continuation command only need to display/process the status :)
+ case "run"
+ case "step_into"
+ case "step_out"
+ case "step_over"
+ case "stop"
+ case "status"
+ return dmh:status($resp)
+
+ default
+ return dmh:report-error(fn:concat("Command not implemented: ", $resp/@command))
+};
+
+declare function dmh:process-init($init as element(init))
+{
+ fn:string-join(
+ ("Established connection with", $init/@language, "client", $init/@appid),
+ " "
+ )
+};
+
+declare function dmh:process($message as element())
+{
+ let $nodeName := fn:local-name($message)
+ let $id := fn:data($message/@transaction_id)
+ return
+ if ($nodeName eq "response") then
+ (: no transaction_id :)
+ if (fn:count($id) eq 0 or $id eq "") then
+ (0, dmh:report-error("Invalid response", "Missing or empty response transaction ID."))
+ (: wrong transaction_id :)
+ else if (xs:string(fn:number($id)) eq "NaN") then
+ (0, dmh:report-error("Invalid response", "Invalid value for response transaction ID."))
+ (: no or empty command :)
+ else if (fn:count($message/@command) eq 0 or $message/@command eq "") then
+ ($id, dmh:report-error("Invalid response", "Missing or empty response command attribute."))
+ (: error response :)
+ else if (fn:exists($message/error)) then
+ ($id, dmh:report-error(fn:data($message/error/message), fn:concat("Error code: ", fn:data($message/error/@code))))
+ else
+ ($id, dmh:process-response($message))
+ else if ($nodeName eq "init") then
+ (0, dmh:process-init($message))
+ else
+ (
+ if (fn:count($id) eq 0 or $id eq "" or xs:string(fn:number($id)) eq "NaN") then
+ 0
+ else
+ $id,
+ dmh:report-error(fn:concat("Unknown message node: ", $nodeName))
+ )
+};
=== modified file 'src/compiler/expression/expr.cpp'
--- src/compiler/expression/expr.cpp 2011-12-13 03:38:23 +0000
+++ src/compiler/expression/expr.cpp 2011-12-13 11:51:46 +0000
@@ -1469,7 +1469,6 @@
compute_scripting_kind();
}
-
void debugger_expr::serialize(::zorba::serialization::Archiver& ar)
{
serialize_baseclass(ar, (expr*)this);
=== modified file 'src/compiler/translator/translator.cpp'
--- src/compiler/translator/translator.cpp 2011-12-13 03:38:23 +0000
+++ src/compiler/translator/translator.cpp 2011-12-13 11:51:46 +0000
@@ -1671,7 +1671,7 @@
void wrap_in_debugger_expr(
expr_t& aExpr,
const QueryLoc& aLoc,
- bool aAddBreakable = true,
+ bool aIsMainModuleBreakable = false,
bool aIsVarDeclaration = false)
{
#ifdef ZORBA_WITH_DEBUGGER
@@ -1686,9 +1686,7 @@
// add the breakable expression in the debugger commons as a possible
// breakpoint location
Breakable lBreakable(aLoc);
- if (aAddBreakable) {
- theCCB->theDebuggerCommons->addBreakable(lBreakable);
- }
+ theCCB->theDebuggerCommons->addBreakable(lBreakable, aIsMainModuleBreakable);
// retrieve all variables that are in the current scope
typedef std::vector<var_expr_t> VarExprVector;
@@ -2246,7 +2244,7 @@
// the main module debug iterator has no location otherwise
// this would take precedence over a child debug iterator
// starting in the same line
- wrap_in_debugger_expr(program, program->get_loc(), false);
+ wrap_in_debugger_expr(program, program->get_loc(), true);
program = wrap_in_globalvar_assign(program);
@@ -3725,7 +3723,7 @@
QueryLoc lExpandedLocation = expandQueryLoc(v.get_name()->get_location(),
initExpr->get_loc());
- wrap_in_debugger_expr(initExpr, lExpandedLocation, true, true);
+ wrap_in_debugger_expr(initExpr, lExpandedLocation, false, true);
}
#endif
@@ -3747,7 +3745,7 @@
QueryLoc lExpandedLocation = expandQueryLoc(v.get_name()->get_location(),
initExpr->get_loc());
- wrap_in_debugger_expr(initExpr, lExpandedLocation, true, true);
+ wrap_in_debugger_expr(initExpr, lExpandedLocation, false, true);
}
#endif
=== modified file 'src/debugger/debugger_client.cpp'
--- src/debugger/debugger_client.cpp 2011-06-14 17:26:33 +0000
+++ src/debugger/debugger_client.cpp 2011-12-13 11:51:46 +0000
@@ -38,5 +38,3 @@
}
}//end of namespace
-
-/* vim:set et sw=2 ts=2: */
=== modified file 'src/debugger/debugger_clientimpl.cpp'
--- src/debugger/debugger_clientimpl.cpp 2011-07-06 20:43:46 +0000
+++ src/debugger/debugger_clientimpl.cpp 2011-12-13 11:51:46 +0000
@@ -24,462 +24,549 @@
namespace zorba {
- DebuggerClient::~DebuggerClient()
- {}
-
- DebuggerClient* DebuggerClient::createDebuggerClient(DebuggerEventHandler* aHandler,
- unsigned short aPort,
- const std::string& aHost)
- {
- return new DebuggerClientImpl(aHost, aPort, aHandler);
- }
-
- DebuggerListener::DebuggerListener(DebuggerClientImpl* aClient)
+DebuggerClient*
+DebuggerClient::createDebuggerClient(
+ DebuggerEventHandler* aHandler,
+ unsigned short aPort,
+ const std::string& aHost)
+{
+ return new DebuggerClientImpl(aHost, aPort, aHandler);
+}
+
+// ****************************************************************************
+
+DebuggerListener::DebuggerListener(DebuggerClientImpl* aClient)
: theClient(aClient), theStopLooping(false)
- {
- }
-
- void DebuggerListener::run()
- {
- while (!theStopLooping) {
- std::string str;
- std::getline(*(theClient->theStream), str, '\0');
-#ifndef NDEBUG
- std::stringstream lStr(str);
- std::size_t length;
- lStr >> length;
-#endif
- // we are not interested in the length, but only in the init
- // message
- std::getline(*(theClient->theStream), str, '\0');
-#ifndef NDEBUG
- assert(str.size() == length);
-#endif
- theClient->theHandler->parseMessage(str);
- this->sleep_(1000);
- }
- }
-
- void DebuggerListener::finish()
- {
- }
-
- void DebuggerListener::stopLooping()
- {
- theStopLooping = true;
- }
-
- DebuggerClientImpl::DebuggerClientImpl(const std::string& aHost,
- unsigned short aPort,
- DebuggerEventHandler* aHandler)
- : theServerSocket(aHost, aPort), theSocket(0), theStreamBuffer(0), theStream(0),
- theHandler(aHandler), theListener(this), theLastId(0)
- {
- }
-
- void DebuggerClientImpl::accept() {
- theSocket = theServerSocket.accept();
- theStreamBuffer = new socket_streambuf(*theSocket);
- theStream = new std::iostream(theStreamBuffer);
- theListener.start();
- }
-
- std::size_t DebuggerClientImpl::status()
- {
- std::size_t id = ++theLastId;
- *theStream << "status -i " << id << '\0';
- theStream->sync();
- return id;
- }
-
- std::size_t DebuggerClientImpl::feature_get(std::string const& aFeatureName)
- {
- std::size_t id = ++theLastId;
- *theStream << "feature-get -i " << id << " -n " << aFeatureName << '\0';
- theStream->sync();
- return id;
- }
-
- std::size_t DebuggerClientImpl::feature_set(std::string const &aFeatureName,
- std::string const &aValue)
- {
- std::size_t id = ++theLastId;
- *theStream << "feature-set -i " << id << " -n " << aFeatureName << " -v "
- << aValue << '\0';
- theStream->sync();
- return id;
- }
-
- std::size_t DebuggerClientImpl::run()
- {
- std::size_t id = ++theLastId;
- *theStream << "run -i " << id << '\0';
- theStream->sync();
- return id;
- }
-
- std::size_t DebuggerClientImpl::step_into()
- {
- std::size_t id = ++theLastId;
- *theStream << "step_into -i " << id << '\0';
- theStream->sync();
- return id;
- }
-
- std::size_t DebuggerClientImpl::step_over()
- {
- std::size_t id = ++theLastId;
- *theStream << "step_over -i " << id << '\0';
- theStream->sync();
- return id;
- }
-
- std::size_t DebuggerClientImpl::step_out()
- {
- std::size_t id = ++theLastId;
- *theStream << "step_out -i " << id << '\0';
- theStream->sync();
- return id;
- }
-
- std::size_t DebuggerClientImpl::stop()
- {
- std::size_t id = ++theLastId;
- *theStream << "stop -i " << id << '\0';
- theStream->sync();
- return id;
- }
-
- std::size_t DebuggerClientImpl::detach()
- {
- std::size_t id = ++theLastId;
- *theStream << "detach -i " << id << '\0';
- theStream->sync();
- return id;
- }
-
- std::size_t DebuggerClientImpl::breakpoint_set(BreakpointType aType,
- bool aEnabled,
- const std::string& aFilename,
- int aLinenumber,
- const std::string& aFunctionName,
- const std::string& aExceptionName,
- unsigned hit_value,
- HitCondition aCondition,
- bool aIsTemporary,
- const std::string& aExpression)
- {
- std::size_t id = ++theLastId;
- *theStream << "breakpoint_set -i " << id
- << " -t ";
- switch (aType) {
- case Line:
- *theStream << "line";
- break;
- case Call:
- *theStream << "call";
- break;
- case Return:
- *theStream << "return";
- break;
- case Exception:
- *theStream << "exception";
- break;
- case Conditional:
- *theStream << "conditional";
- break;
- case Watch:
- *theStream << "watch";
- break;
- }
- if (!aEnabled)
- *theStream << " -s disabled";
- if (aFilename != "") {
- *theStream << " -f " << aFilename;
- }
- if (aLinenumber != -1)
- *theStream << " -n " << aLinenumber;
- if (aFunctionName != "")
- *theStream << " -m " << aFunctionName;
- if (aExceptionName != "")
- *theStream << " -x " << aExceptionName;
- if (hit_value != 0)
- *theStream << " -h " << hit_value;
- switch (aCondition) {
- case BiggerEqual:
- break;
- case Equal:
- *theStream << " -o == ";
- break;
- case Multiple:
- *theStream << " -o % ";
- }
- if (aIsTemporary)
- *theStream << " -r 1 ";
- if (aExpression != "")
- *theStream << " -- " << aExpression;
- *theStream << '\0';
- theStream->sync();
- return id;
- }
-
- std::size_t DebuggerClientImpl::breakpoint_get(std::size_t aBreakpointId)
- {
- std::size_t id = ++theLastId;
- *theStream << "breakpoint_get -i " << id << " -d " << aBreakpointId << '\0';
- theStream->sync();
- return id;
- }
-
- std::size_t DebuggerClientImpl::breakpoint_update(std::size_t aBreakpointId,
- bool aEnabled,
- int aLinenumber,
- unsigned hit_value,
- HitCondition aCondition)
- {
- std::size_t id = ++theLastId;
- *theStream << "breakpoint_update -i " << id
- << " -d " << aBreakpointId;
- if (aEnabled)
- *theStream << " -s disabled";
- if (aLinenumber != -1)
- *theStream << " -n " << aLinenumber;
- if (hit_value != 0)
- *theStream << " -h " << hit_value;
- switch (aCondition) {
- case BiggerEqual:
- break;
- case Equal:
- *theStream << " -o == ";
- break;
- case Multiple:
- *theStream << " -o % ";
- }
- *theStream << '\0';
- theStream->sync();
- return id;
- }
-
- std::size_t DebuggerClientImpl::breakpoint_remove(std::size_t aBreakpointId)
- {
- std::size_t id = ++theLastId;
- *theStream << "breakpoint_remove -i " << id << " -d " << aBreakpointId << '\0';
- theStream->sync();
- return id;
- }
-
- std::size_t DebuggerClientImpl::breakpoint_list()
- {
- std::size_t id = ++theLastId;
- *theStream << "breakpoint_list -i " << id << '\0';
- theStream->sync();
- return id;
- }
-
- std::size_t DebuggerClientImpl::stack_depth()
- {
- std::size_t id = ++theLastId;
- *theStream << "stack_depth -i " << id << '\0';
- theStream->sync();
- return id;
- }
-
- std::size_t DebuggerClientImpl::stack_get(int depth)
- {
- std::size_t id = ++theLastId;
- *theStream << "stack_depth";
- if (depth > 0)
- *theStream << " -d " << depth;
- *theStream << " -i " << id << '\0';
- theStream->sync();
- return id;
- }
-
- std::size_t DebuggerClientImpl::context_names(int depth)
- {
- std::size_t id = ++theLastId;
- *theStream << "context_names";
- if (depth > 0)
- *theStream << " -d " << depth;
- *theStream << " -i " << id << '\0';
- theStream->sync();
- return id;
- }
-
- std::size_t DebuggerClientImpl::context_get(int depth, int contextId)
- {
- std::size_t id = ++theLastId;
- *theStream << "context_get";
- if (depth > 0)
- *theStream << " -d " << depth;
- if (contextId > 0)
- *theStream << " -c " << contextId;
- *theStream << " -i " << id << '\0';
- theStream->sync();
- return id;
- }
-
- std::size_t DebuggerClientImpl::typemap_get()
- {
- std::size_t id = ++theLastId;
- *theStream << "typemap_get -i " << id << '\0';
- theStream->sync();
- return id;
- }
-
- std::size_t DebuggerClientImpl::property_get(const std::string& aPropertyLongName,
- int aStackDepth,
- int aContextId,
- std::size_t aMaxDataSize,
- int aDatapage,
- const std::string& aPropertyKey)
- {
- std::size_t id = property_x("property_get", aPropertyLongName, aStackDepth, aContextId, aMaxDataSize);
- if (aDatapage >= 0)
- *theStream << " -p " << aDatapage;
- if (aPropertyKey != "")
- *theStream << " -k " << aPropertyKey;
- *theStream << '\0';
- theStream->sync();
- return id;
- }
-
- std::size_t DebuggerClientImpl::property_set(const std::string& aPropertyLongName,
- int aStackDepth,
- int aContextId,
- std::size_t aMaxDataSize,
- const std::string& aPropertyAddress)
- {
- std::size_t id = property_x("property_set", aPropertyLongName, aStackDepth, aContextId, aMaxDataSize);
- if (aPropertyAddress != "")
- *theStream << " -a " << aPropertyAddress;
- *theStream << '\0';
- theStream->sync();
- return id;
- }
-
- std::size_t DebuggerClientImpl::property_value(const std::string& aPropertyLongName,
- int aStackDepth,
- int aContextId,
- std::size_t aMaxDataSize,
- int aDatapage,
- const std::string& aPropertyKey,
- const std::string& aPropertyAddress)
- {
- std::size_t id = property_x("property_get", aPropertyLongName, aStackDepth, aContextId, aMaxDataSize);
- if (aDatapage >= 0)
- *theStream << " -p " << aDatapage;
- if (aPropertyKey != "")
- *theStream << " -k " << aPropertyKey;
- if (aPropertyAddress != "")
- *theStream << " -a " << aPropertyAddress;
- *theStream << '\0';
- theStream->sync();
- return id;
- }
-
- std::size_t DebuggerClientImpl::property_x(const std::string& aCommand,
- const std::string& aPropertyLongName,
- int aStackDepth,
- int aContextId,
- std::size_t aMaxDataSize)
- {
- std::size_t id = ++theLastId;
- *theStream << aCommand << " -i " << id << " -n " << aPropertyLongName;
- if (aStackDepth > 0)
- *theStream << " -d " << aStackDepth;
- if (aContextId > 0)
- *theStream << " -c " << aContextId;
- if (aMaxDataSize > 0)
- *theStream << " -m " << aMaxDataSize;
- theStream->sync();
- return id;
- }
-
- std::size_t DebuggerClientImpl::source(std::string const &aFile,
- unsigned int aBeginLine,
- unsigned int aEndLine)
- {
- std::size_t id = ++theLastId;
- *theStream << "source -i " << id << " -f " << aFile;
- if (aBeginLine)
- *theStream << " -b " << aBeginLine;
- if (aEndLine)
- *theStream << " -e " << aEndLine;
- *theStream << '\0';
- theStream->sync();
- return id;
- }
-
- std::size_t DebuggerClientImpl::stream_option(OutputStream aStream, StreamBehaviour aBehaviour)
- {
- std::size_t id = ++theLastId;
- switch (aStream) {
- case Stdout:
- *theStream << "stdout";
- break;
- case Stderr:
- *theStream << "stderr";
- break;
- case Stdin:
- *theStream << "stdin";
- break;
- }
- *theStream << " -i " << id << " -c ";
- switch (aBehaviour) {
- case Disable:
- *theStream << "0";
- break;
- case CopyData:
- *theStream << "1";
- break;
- case Redirection:
- *theStream << "2";
- break;
- }
- *theStream << '\0';
- theStream->sync();
- return id;
- }
-
- std::size_t DebuggerClientImpl::do_break()
- {
- std::size_t id = ++theLastId;
- *theStream << "break -i " << id << '\0';
- theStream->sync();
- return id;
- }
-
- std::size_t DebuggerClientImpl::eval(std::string const &aExpr)
- {
- std::size_t id = ++theLastId;
- *theStream << "eval -i " << id << " -- " << encoding::Base64::encode(aExpr.c_str()) << '\0';
- theStream->sync();
- return id;
- }
-
- void DebuggerClientImpl::quit() {
- theListener.stopLooping();
- theListener.join();
- }
-
-
-
- DebuggerClientImpl::~DebuggerClientImpl()
- {
- if (theListener.status() == DebuggerListener::RUNNING) {
- theListener.stopLooping();
- theListener.join();
- }
- if (theSocket) {
- theSocket->close();
- theSocket->cleanUp();
- delete theSocket;
- }
- if (theStream) {
- theStream->sync();
- delete theStream;
- delete theStreamBuffer;
- }
- }
-}
+{
+}
+
+void
+DebuggerListener::run()
+{
+ while (!theStopLooping) {
+ std::string str;
+ std::getline(*(theClient->theInStream), str, '\0');
+
+#ifndef NDEBUG
+ std::stringstream lStr(str);
+ std::size_t length;
+ lStr >> length;
+#endif
+
+ // we are not interested in the length, but only in the init message
+ std::getline(*(theClient->theInStream), str, '\0');
+
+#ifndef NDEBUG
+ assert(str.size() == length);
+#endif
+
+ theClient->theHandler->parseMessage(str);
+
+ // TODO: this was the initial implementation. This will have to change
+ this->sleep_(1000);
+ }
+}
+
+void
+DebuggerListener::finish()
+{
+}
+
+void
+DebuggerListener::stopLooping()
+{
+ theStopLooping = true;
+}
+
+// ****************************************************************************
+
+DebuggerClient::~DebuggerClient()
+{
+}
+
+DebuggerClientImpl::DebuggerClientImpl(
+ const std::string& aHost,
+ unsigned short aPort,
+ DebuggerEventHandler* aHandler)
+ : theServerSocket(aHost, aPort),
+ theSocket(0),
+ theInStreamBuffer(0),
+ theOutStreamBuffer(0),
+ theInStream(0),
+ theOutStream(0),
+ theHandler(aHandler),
+ theListener(0),
+ theLastId(0)
+{
+}
+
+DebuggerClientImpl::~DebuggerClientImpl()
+{
+ if (theListener) {
+ if (theListener->status() == DebuggerListener::RUNNING) {
+ theListener->stopLooping();
+ theListener->join();
+ }
+ delete theListener;
+ }
+ if (theSocket) {
+ theInStream->sync();
+ delete theInStream;
+
+ theOutStream->flush();
+ delete theInStream;
+
+ delete theOutStreamBuffer;
+ delete theInStreamBuffer;
+
+ theSocket->close();
+ theSocket->cleanUp();
+ delete theSocket;
+ }
+}
+
+void
+DebuggerClientImpl::accept()
+{
+ theListener = new DebuggerListener(this);
+ theSocket = theServerSocket.accept();
+ theInStreamBuffer = new SocketStreambuf(*theSocket);
+ theOutStreamBuffer = new SocketStreambuf(*theSocket);
+ theInStream = new std::istream(theInStreamBuffer);
+ theOutStream = new std::ostream(theOutStreamBuffer);
+ theListener->start();
+}
+
+std::size_t
+DebuggerClientImpl::status()
+{
+ std::size_t id = ++theLastId;
+ *theOutStream << "status -i " << id << '\0';
+ theOutStream->flush();
+ return id;
+}
+
+std::size_t
+DebuggerClientImpl::variables()
+{
+ // we hack the protocol to return all properties if the context ID is -1
+ std::size_t id = ++theLastId;
+ *theOutStream << "context_get -c -1 -i " << id << '\0';
+ theOutStream->flush();
+ return id;
+}
+
+std::size_t
+DebuggerClientImpl::feature_get(std::string const& aFeatureName)
+{
+ std::size_t id = ++theLastId;
+ *theOutStream << "feature_get -i " << id << " -n " << aFeatureName << '\0';
+ theOutStream->flush();
+ return id;
+}
+
+std::size_t
+DebuggerClientImpl::feature_set(std::string const &aFeatureName,
+ std::string const &aValue)
+{
+ std::size_t id = ++theLastId;
+ *theOutStream << "feature_set -i " << id << " -n " << aFeatureName << " -v "
+ << aValue << '\0';
+ theOutStream->flush();
+ return id;
+}
+
+std::size_t
+DebuggerClientImpl::run()
+{
+ std::size_t id = ++theLastId;
+ *theOutStream << "run -i " << id << '\0';
+ theOutStream->flush();
+ return id;
+}
+
+std::size_t
+DebuggerClientImpl::step_into()
+{
+ std::size_t id = ++theLastId;
+ *theOutStream << "step_into -i " << id << '\0';
+ theOutStream->flush();
+ return id;
+}
+
+std::size_t
+DebuggerClientImpl::step_over()
+{
+ std::size_t id = ++theLastId;
+ *theOutStream << "step_over -i " << id << '\0';
+ theOutStream->flush();
+ return id;
+}
+
+std::size_t
+DebuggerClientImpl::step_out()
+{
+ std::size_t id = ++theLastId;
+ *theOutStream << "step_out -i " << id << '\0';
+ theOutStream->flush();
+ return id;
+}
+
+std::size_t
+DebuggerClientImpl::stop()
+{
+ std::size_t id = ++theLastId;
+ *theOutStream << "stop -i " << id << '\0';
+ theOutStream->flush();
+ return id;
+}
+
+std::size_t
+DebuggerClientImpl::detach()
+{
+ std::size_t id = ++theLastId;
+ *theOutStream << "detach -i " << id << '\0';
+ theOutStream->flush();
+ return id;
+}
+
+std::size_t
+DebuggerClientImpl::breakpoint_set(
+ BreakpointType aType,
+ bool aEnabled,
+ const std::string& aFilename,
+ int aLinenumber,
+ const std::string& aFunctionName,
+ const std::string& aExceptionName,
+ unsigned hit_value,
+ HitCondition aCondition,
+ bool aIsTemporary,
+ const std::string& aExpression)
+{
+ std::size_t id = ++theLastId;
+ *theOutStream << "breakpoint_set -i " << id
+ << " -t ";
+ switch (aType) {
+ case Line:
+ *theOutStream << "line";
+ break;
+ case Call:
+ *theOutStream << "call";
+ break;
+ case Return:
+ *theOutStream << "return";
+ break;
+ case Exception:
+ *theOutStream << "exception";
+ break;
+ case Conditional:
+ *theOutStream << "conditional";
+ break;
+ case Watch:
+ *theOutStream << "watch";
+ break;
+ }
+ if (!aEnabled)
+ *theOutStream << " -s disabled";
+ if (aFilename != "") {
+ *theOutStream << " -f \"" << aFilename << "\"";
+ }
+ if (aLinenumber != -1)
+ *theOutStream << " -n " << aLinenumber;
+ if (aFunctionName != "")
+ *theOutStream << " -m " << aFunctionName;
+ if (aExceptionName != "")
+ *theOutStream << " -x " << aExceptionName;
+ if (hit_value != 0)
+ *theOutStream << " -h " << hit_value;
+ switch (aCondition) {
+ case BiggerEqual:
+ break;
+ case Equal:
+ *theOutStream << " -o == ";
+ break;
+ case Multiple:
+ *theOutStream << " -o % ";
+ }
+ if (aIsTemporary)
+ *theOutStream << " -r 1 ";
+ if (aExpression != "")
+ *theOutStream << " -- " << aExpression;
+ *theOutStream << '\0';
+ theOutStream->flush();
+ return id;
+}
+
+std::size_t
+DebuggerClientImpl::breakpoint_get(std::size_t aBreakpointId)
+{
+ std::size_t id = ++theLastId;
+ *theOutStream << "breakpoint_get -i " << id << " -d " << aBreakpointId << '\0';
+ theOutStream->flush();
+ return id;
+}
+
+std::size_t
+DebuggerClientImpl::breakpoint_update(
+ std::size_t aBreakpointId,
+ bool aEnabled,
+ int aLinenumber,
+ unsigned hit_value,
+ HitCondition aCondition)
+{
+ std::size_t id = ++theLastId;
+ *theOutStream << "breakpoint_update -i " << id
+ << " -d " << aBreakpointId;
+ if (aEnabled)
+ *theOutStream << " -s disabled";
+ if (aLinenumber != -1)
+ *theOutStream << " -n " << aLinenumber;
+ if (hit_value != 0)
+ *theOutStream << " -h " << hit_value;
+ switch (aCondition) {
+ case BiggerEqual:
+ break;
+ case Equal:
+ *theOutStream << " -o == ";
+ break;
+ case Multiple:
+ *theOutStream << " -o % ";
+ }
+ *theOutStream << '\0';
+ theOutStream->flush();
+ return id;
+}
+
+std::size_t
+DebuggerClientImpl::breakpoint_remove(std::size_t aBreakpointId)
+{
+ std::size_t id = ++theLastId;
+ *theOutStream << "breakpoint_remove -i " << id << " -d " << aBreakpointId << '\0';
+ theOutStream->flush();
+ return id;
+}
+
+std::size_t
+DebuggerClientImpl::breakpoint_list()
+{
+ std::size_t id = ++theLastId;
+ *theOutStream << "breakpoint_list -i " << id << '\0';
+ theOutStream->flush();
+ return id;
+}
+
+std::size_t
+DebuggerClientImpl::stack_depth()
+{
+ std::size_t id = ++theLastId;
+ *theOutStream << "stack_depth -i " << id << '\0';
+ theOutStream->flush();
+ return id;
+}
+
+std::size_t
+DebuggerClientImpl::stack_get(int depth)
+{
+ std::size_t id = ++theLastId;
+ *theOutStream << "stack_get";
+ if (depth >= 0) {
+ *theOutStream << " -d " << depth;
+ }
+ *theOutStream << " -i " << id << '\0';
+ theOutStream->flush();
+ return id;
+}
+
+std::size_t
+DebuggerClientImpl::context_names(int depth)
+{
+ std::size_t id = ++theLastId;
+ *theOutStream << "context_names";
+ if (depth >= 0) {
+ *theOutStream << " -d " << depth;
+ }
+ *theOutStream << " -i " << id << '\0';
+ theOutStream->flush();
+ return id;
+}
+
+std::size_t
+DebuggerClientImpl::context_get(int depth, int contextId)
+{
+ std::size_t id = ++theLastId;
+ *theOutStream << "context_get";
+ if (depth >= 0) {
+ *theOutStream << " -d " << depth;
+ }
+ if (contextId >= 0){
+ *theOutStream << " -c " << contextId;
+ }
+ *theOutStream << " -i " << id << '\0';
+ theOutStream->flush();
+ return id;
+}
+
+std::size_t
+DebuggerClientImpl::typemap_get()
+{
+ std::size_t id = ++theLastId;
+ *theOutStream << "typemap_get -i " << id << '\0';
+ theOutStream->flush();
+ return id;
+}
+
+std::size_t
+DebuggerClientImpl::property_get(
+ const std::string& aPropertyLongName,
+ int aStackDepth,
+ int aContextId,
+ std::size_t aMaxDataSize,
+ int aDatapage,
+ const std::string& aPropertyKey)
+{
+ std::size_t id = property_x("property_get", aPropertyLongName, aStackDepth, aContextId, aMaxDataSize);
+ if (aDatapage >= 0)
+ *theOutStream << " -p " << aDatapage;
+ if (aPropertyKey != "")
+ *theOutStream << " -k " << aPropertyKey;
+ *theOutStream << '\0';
+ theOutStream->flush();
+ return id;
+}
+
+std::size_t
+DebuggerClientImpl::property_set(
+ const std::string& aPropertyLongName,
+ int aStackDepth,
+ int aContextId,
+ std::size_t aMaxDataSize,
+ const std::string& aPropertyAddress)
+{
+ std::size_t id = property_x("property_set", aPropertyLongName, aStackDepth, aContextId, aMaxDataSize);
+ if (aPropertyAddress != "")
+ *theOutStream << " -a " << aPropertyAddress;
+ *theOutStream << '\0';
+ theOutStream->flush();
+ return id;
+}
+
+std::size_t
+DebuggerClientImpl::property_value(
+ const std::string& aPropertyLongName,
+ int aStackDepth,
+ int aContextId,
+ std::size_t aMaxDataSize,
+ int aDatapage,
+ const std::string& aPropertyKey,
+ const std::string& aPropertyAddress)
+{
+ std::size_t id = property_x("property_get", aPropertyLongName, aStackDepth, aContextId, aMaxDataSize);
+ if (aDatapage >= 0)
+ *theOutStream << " -p " << aDatapage;
+ if (aPropertyKey != "")
+ *theOutStream << " -k " << aPropertyKey;
+ if (aPropertyAddress != "")
+ *theOutStream << " -a " << aPropertyAddress;
+ *theOutStream << '\0';
+ theOutStream->flush();
+ return id;
+}
+
+std::size_t
+DebuggerClientImpl::property_x(
+ const std::string& aCommand,
+ const std::string& aPropertyLongName,
+ int aStackDepth,
+ int aContextId,
+ std::size_t aMaxDataSize)
+{
+ std::size_t id = ++theLastId;
+ *theOutStream << aCommand << " -i " << id << " -n " << aPropertyLongName;
+ if (aStackDepth > 0)
+ *theOutStream << " -d " << aStackDepth;
+ if (aContextId > 0)
+ *theOutStream << " -c " << aContextId;
+ if (aMaxDataSize > 0)
+ *theOutStream << " -m " << aMaxDataSize;
+ theOutStream->flush();
+ return id;
+}
+
+std::size_t
+DebuggerClientImpl::source(
+ std::string const &aFile,
+ unsigned int aBeginLine,
+ unsigned int aEndLine)
+{
+ std::size_t id = ++theLastId;
+ *theOutStream << "source -i " << id;
+ // enable zorba extensions
+ *theOutStream << " -z 1";
+ *theOutStream << " -f \"" << aFile << "\"";
+ if (aBeginLine)
+ *theOutStream << " -b " << aBeginLine;
+ if (aEndLine)
+ *theOutStream << " -e " << aEndLine;
+ *theOutStream << '\0';
+ theOutStream->flush();
+ return id;
+}
+
+std::size_t
+DebuggerClientImpl::stream_option(OutputStream aStream, StreamBehaviour aBehaviour)
+{
+ std::size_t id = ++theLastId;
+ switch (aStream) {
+ case Stdout:
+ *theOutStream << "stdout";
+ break;
+ case Stderr:
+ *theOutStream << "stderr";
+ break;
+ case Stdin:
+ *theOutStream << "stdin";
+ break;
+ }
+ *theOutStream << " -i " << id << " -c ";
+ switch (aBehaviour) {
+ case Disable:
+ *theOutStream << "0";
+ break;
+ case CopyData:
+ *theOutStream << "1";
+ break;
+ case Redirection:
+ *theOutStream << "2";
+ break;
+ }
+ *theOutStream << '\0';
+ theOutStream->flush();
+ return id;
+}
+
+std::size_t
+DebuggerClientImpl::do_break()
+{
+ std::size_t id = ++theLastId;
+ *theOutStream << "break -i " << id << '\0';
+ theOutStream->flush();
+ return id;
+}
+
+std::size_t
+DebuggerClientImpl::eval(std::string const &aExpr)
+{
+ std::size_t id = ++theLastId;
+ *theOutStream << "eval -i " << id << " -- " << encoding::Base64::encode(aExpr.c_str()) << '\0';
+ theOutStream->flush();
+ return id;
+}
+
+void
+DebuggerClientImpl::quit()
+{
+ theListener->stopLooping();
+ theListener->join();
+}
+
+} // namespace zorba
=== modified file 'src/debugger/debugger_clientimpl.h'
--- src/debugger/debugger_clientimpl.h 2011-07-01 01:53:24 +0000
+++ src/debugger/debugger_clientimpl.h 2011-12-13 11:51:46 +0000
@@ -13,7 +13,8 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-#pragma once
+#ifndef ZORBA_DEBUGGER_CLIENTIMPL_H
+#define ZORBA_DEBUGGER_CLIENTIMPL_H
#include <string>
#include <zorba/debugger_client.h>
@@ -21,7 +22,7 @@
#include "zorbautils/runnable.h"
namespace zorba {
- class socket_streambuf;
+ class SocketStreambuf;
class DebuggerEventHandler;
class DebuggerListener;
class DebuggerClientImpl;
@@ -48,6 +49,7 @@
public: // API
virtual void accept();
virtual std::size_t status();
+ virtual std::size_t variables();
virtual std::size_t feature_get(const std::string& aFeatureName);
virtual std::size_t feature_set(const std::string& aFeatureName,
const std::string& aValue);
@@ -110,12 +112,17 @@
int aContextId = -1,
std::size_t aMaxDataSize = 0);
private:
- TCPServerSocket theServerSocket;
- TCPSocket* theSocket;
- socket_streambuf* theStreamBuffer;
- std::iostream* theStream;
+ TCPServerSocket theServerSocket;
+ TCPSocket* theSocket;
+ SocketStreambuf* theInStreamBuffer;
+ SocketStreambuf* theOutStreamBuffer;
+ std::istream* theInStream;
+ std::ostream* theOutStream;
DebuggerEventHandler* theHandler;
- DebuggerListener theListener;
- std::size_t theLastId;
+ DebuggerListener* theListener;
+ std::size_t theLastId;
};
-}
+
+} // namespace zorba
+
+#endif // ZORBA_DEBUGGER_CLIENTIMPL_H
=== modified file 'src/debugger/debugger_common.h'
--- src/debugger/debugger_common.h 2011-06-22 11:19:07 +0000
+++ src/debugger/debugger_common.h 2011-12-13 11:51:46 +0000
@@ -20,22 +20,15 @@
#include "common/common.h"
/* Type definitions */
-typedef unsigned char StepCommand;
typedef unsigned char ExecutionStatus;
typedef unsigned short SuspensionCause;
-/* Kind of step command */
-const StepCommand STEP_INTO = 0x01;
-const StepCommand STEP_OUT = 0x02;
-const StepCommand STEP_OVER = 0x03;
-
/* Status of the engine */
const ExecutionStatus QUERY_IDLE = 0x01;
const ExecutionStatus QUERY_RUNNING = 0x02;
-const ExecutionStatus QUERY_RESUMED = 0x03;
-const ExecutionStatus QUERY_SUSPENDED = 0x04;
-const ExecutionStatus QUERY_TERMINATED = 0x05;
-const ExecutionStatus QUERY_DETACHED = 0x06;
+const ExecutionStatus QUERY_SUSPENDED = 0x03;
+const ExecutionStatus QUERY_TERMINATED = 0x04;
+const ExecutionStatus QUERY_DETACHED = 0x05;
/* Cause of the suspension of the engine */
const SuspensionCause CAUSE_USER = 0x01;
=== modified file 'src/debugger/debugger_commons.cpp'
--- src/debugger/debugger_commons.cpp 2011-06-22 11:19:07 +0000
+++ src/debugger/debugger_commons.cpp 2011-12-13 11:51:46 +0000
@@ -151,13 +151,11 @@
theBreakCondition(0),
theExecEval(false),
theStepping(false)
-
{
theRuntime = NULL;
theCurrentStaticContext = NULL;
theCurrentDynamicContext = NULL;
thePlanState = NULL;
- theDebugIteratorState = NULL;
}
DebuggerCommons::~DebuggerCommons()
@@ -185,8 +183,6 @@
if(ar.is_serializing_out())
thePlanState = NULL;
- if(ar.is_serializing_out())
- theDebugIteratorState = NULL;
ar & theEvalItem;
ar & theExecEval;
ar & theStepping;
@@ -230,17 +226,98 @@
}
unsigned int
-DebuggerCommons::addBreakpoint(const QueryLoc& aLocation, bool aEnabled)
+DebuggerCommons::addBreakpoint(String& aFileName, int aLine, bool aEnabled)
{
- BreakableIdMap::iterator lIter = theBreakableIDs.find(aLocation);
+ QueryLoc lLocation;
+ lLocation.setLineBegin(aLine);
+ lLocation.setLineEnd(aLine);
+ lLocation.setFilename(aFileName.c_str());
+
+ // we make sure that the this location file name is aligned with the internal ones
+ // it must have a valid URI and a scheme (file://, http://, or https://)
+ adjustLocationFilePath(lLocation);
+
+ BreakableIdMap::iterator lIter = theBreakableIDs.find(lLocation);
+ unsigned int lId;
if (lIter == theBreakableIDs.end()) {
+ String lFileName = aFileName;
+ // be prepared to throw an exception
std::stringstream lSs;
- lSs << "The breakpoint could not be set at line " << aLocation.getLineBegin()
- << " in file: " << aLocation.getFilename();
- throw lSs.str();
- }
- unsigned int lId = lIter->second;
+ lSs << "The breakpoint could not be set at line " << aLine
+ << " in file \"" << lFileName << "\"";
+
+ // let us then try some search before we fail, be good to the user and help him
+ // 1. first we check if he sent a file URI; in this case, sorry!
+ if (lFileName.find("file://") == 0) {
+ throw lSs.str();
+ }
+
+ // now we have to normalize if we hope to find something
+ lFileName = URIHelper::encodeFileURI(lFileName).str();
+ // remove the added file schema prefix
+ // TODO: maybe there is a better way to do this encoding
+ lFileName = lFileName.substr(8);
+
+ // 2. secondly we hope he gave us part of a path of a file
+ lIter = theBreakableIDs.begin();
+ String::size_type lFileNameSize = lFileName.size();
+ std::vector<std::pair<QueryLoc, int> > lFoundBreakables;
+ zorba::String lFirstBreakablePath;
+ while (lIter != theBreakableIDs.end()) {
+ // for now, only valid if on the breakable is on the same line as requested
+ // TODO: this could be improved if the user wants to add a breakpoint to a line
+ // INSIDE a breakable that spans over multiple lines
+ if (lIter->second != theMainModuleBreakableId && lIter->first.getLineBegin() == aLine) {
+ zorba::String lBreakablePath = lIter->first.getFilename().str();
+
+ // dies the given string matche any part in the breakable file name?
+ if (lBreakablePath.find(lFileName) != String::npos) {
+ // we found the fist candidate path
+ if (lFirstBreakablePath == "") {
+ lFirstBreakablePath = lBreakablePath;
+ }
+ // but stop as soon as we are reaching a second different path (report ambiguity)
+ else if (lFirstBreakablePath != lBreakablePath){
+ lSs.str("");
+ lSs << "The file name \"" << aFileName << "\" is ambiguous. "
+ << "I already found two potential files to set a breakpoint in line " << aLine
+ << ":" << std::endl << " " << lFirstBreakablePath << std::endl << " " << lBreakablePath;
+ throw lSs.str();
+ }
+
+ // Yes! We found one!
+ lFoundBreakables.push_back(std::pair<QueryLoc, int>(lIter->first, lIter->second));
+ }
+ }
+ lIter++;
+ }
+
+ // what should I say, not a very successful search :(
+ if (lFoundBreakables.size() == 0) {
+ throw lSs.str();
+ }
+
+ // TODO: The best solution would be for the debugger to enable all the
+ // matched breakables but the protocol can send back only one ID of the
+ // breakpoint set.
+
+ // so we have multiple breakables, get the first in line
+ // TODO: this does not catch multiple breakables starting in the same line
+ // so only one will be picked (depending how the translator generated them)
+ unsigned int lMinCol = lFoundBreakables.at(0).first.getColumnBegin();
+ lId = lFoundBreakables.at(0).second;
+ for (std::size_t i = 1; i < lFoundBreakables.size(); i++) {
+ if (lMinCol > lFoundBreakables.at(i).first.getColumnBegin()) {
+ lId = lFoundBreakables.at(i).second;
+ }
+ }
+ }
+ else {
+ lId = lIter->second;
+ }
+
+ // now we have a breakable, so set it accordingly
theBreakables[lId].setSet(true);
theBreakables[lId].setEnabled(aEnabled);
return lId;
@@ -253,6 +330,12 @@
return theBreakables[aId];
}
+BreakableVector
+DebuggerCommons::getBreakpoints()
+{
+ return theBreakables;
+}
+
void
DebuggerCommons::checkBreakpoint(unsigned int aId)
{
@@ -338,6 +421,7 @@
bool
DebuggerCommons::hasToBreakAt(QueryLoc aLocation)
{
+ // we make sure that this location file name is a valid URI and has a scheme (file://, http://, or https://)
adjustLocationFilePath(aLocation);
BreakableIdMap::const_iterator lIter = theBreakableIDs.find(aLocation);
@@ -449,14 +533,6 @@
ZORBA_ASSERT(thePlanState == aPlanState);
}
-void
-DebuggerCommons::setDebugIteratorState(DebugIteratorState* aState)
-{
- theDebugIteratorState = aState;
- //Check postconditions
- ZORBA_ASSERT(theDebugIteratorState == aState);
-}
-
std::list<std::pair<zstring, zstring> >
DebuggerCommons::eval(const zstring& aExpr, Zorba_SerializerOptions& aSerOpts)
{
@@ -511,11 +587,17 @@
}
void
-DebuggerCommons::addBreakable(Breakable& aBreakable)
+DebuggerCommons::addBreakable(
+ Breakable& aBreakable,
+ bool aIsMainModuleBreakable)
{
+ // we make sure that this breakable file name is a valid URI and has a scheme (file://, http://, or https://)
adjustLocationFilePath(aBreakable.getLocation());
unsigned int lId = theBreakables.size();
+ if (aIsMainModuleBreakable) {
+ theMainModuleBreakableId = lId;
+ }
theBreakables.push_back(aBreakable);
theBreakableIDs[aBreakable.getLocation()] = lId;
}
@@ -523,6 +605,9 @@
void
DebuggerCommons::pushStackFrame(QueryLoc aLocation, std::string& aFunctionName)
{
+ // we make sure that the stack frame locations always have valid URIs and a scheme (file://, http://, or https://)
+ adjustLocationFilePath(aLocation);
+
theStackTrace.push_back(std::pair<QueryLoc, std::string>(aLocation, aFunctionName));
}
@@ -541,11 +626,24 @@
void
DebuggerCommons::adjustLocationFilePath(QueryLoc& aLocation)
{
- if (aLocation.getFilename().substr(0, 7) == "file://") {
- // adjust the file paths by removing the schema and encoding
- zstring lOldFilename(aLocation.getFilename());
+ zstring lOldFilename(aLocation.getFilename());
+ zstring lPrefix = lOldFilename.substr(0, 7);
+
+ if (lPrefix == "file://") {
+#ifdef WIN32
+ // decode and encode back to solve the driver column encoding: C:, D:, etc.
const String lNewFilename = URIHelper::decodeFileURI(lOldFilename.str());
- aLocation.setFilename(lNewFilename.str());
+ const String lNewURI = URIHelper::encodeFileURI(lNewFilename);
+ aLocation.setFilename(lNewURI.str());
+#endif
+ return;
+ }
+
+ // just encode and assume file for non-URI locations
+ if (lPrefix != "http://" && lPrefix != "https:/") {
+ const String lNewURI = URIHelper::encodeFileURI(lOldFilename.str());
+ aLocation.setFilename(lNewURI.str());
+ return;
}
}
=== modified file 'src/debugger/debugger_commons.h'
--- src/debugger/debugger_commons.h 2011-06-22 11:19:07 +0000
+++ src/debugger/debugger_commons.h 2011-12-13 11:51:46 +0000
@@ -19,14 +19,17 @@
#include <map>
#include <string>
+#include <zorba/util/uri.h>
+#include <zorba/zorba_string.h>
+
#include "compiler/parser/query_loc.h"
#include "runtime/core/item_iterator.h"
#include "zorbaserialization/serialization_engine.h"
#include "zorbatypes/zstring.h"
-#include "debugger/debugger_common.h"
-#include "debugger/query_locationimpl.h"
+#include "debugger_common.h"
+#include "query_locationimpl.h"
struct Zorba_SerializerOptions;
@@ -208,16 +211,6 @@
void setPlanState(PlanState* aPlanState);
/**
- * @brief Sets the current debugger state.
- *
- * When the debugger suspends, it saves its state.
- *
- * @param aState a pointer to the current debugger state.
- * @post aState == theDebugIteratorState
- */
- void setDebugIteratorState(DebugIteratorState* aState);
-
- /**
* @brief Sets a setpoint according to the step out rules.
*
* This method sets a breakpoint according to the rules according to
@@ -245,11 +238,14 @@
public:
unsigned int
- addBreakpoint(const QueryLoc& location, bool enabled);
+ addBreakpoint(String& fileName, int line, bool enabled);
Breakable
getBreakpoint(unsigned int id);
+ BreakableVector
+ getBreakpoints();
+
void
updateBreakpoint(unsigned int id, bool enabled);
@@ -336,7 +332,7 @@
std::string getFilepathOfURI(const std::string& aUri) const;
void
- addBreakable(Breakable& location);
+ addBreakable(Breakable& location, bool isMainModuleBreakable = false);
void
pushStackFrame(QueryLoc location, std::string& functionName);
@@ -384,10 +380,10 @@
std::vector<DebugIterator*> theIteratorStack;
std::size_t theBreakCondition;
PlanState* thePlanState;
- DebugIteratorState* theDebugIteratorState;
store::Item_t theEvalItem;
bool theExecEval;
bool theStepping;
+ unsigned int theMainModuleBreakableId;
};
}
=== modified file 'src/debugger/debugger_communicator.cpp'
--- src/debugger/debugger_communicator.cpp 2011-07-29 23:01:30 +0000
+++ src/debugger/debugger_communicator.cpp 2011-12-13 11:51:46 +0000
@@ -77,15 +77,15 @@
void
DebuggerCommunicator::connect()
{
- for (int i = 0; i < 3 && !theSocket; i++)
+ for (int i = 0; i < 5 && !theSocket; i++)
{
try
{
// Connect to the client on the given host and port
std::auto_ptr<TCPSocket> lSocket(new TCPSocket(theHost, thePort));
theSocket = lSocket.release();
- theSocketInStream = new socket_streambuf(*theSocket);
- theSocketOutStream = new socket_streambuf(*theSocket);
+ theSocketInStream = new SocketStreambuf(*theSocket);
+ theSocketOutStream = new SocketStreambuf(*theSocket);
theCommunicatorInStream = new std::istream(theSocketInStream);
theCommunicatorOutStream = new std::ostream(theSocketOutStream);
theResponseQueue = new ResponseQueue(theCommunicatorOutStream);
=== modified file 'src/debugger/debugger_communicator.h'
--- src/debugger/debugger_communicator.h 2011-07-01 16:07:54 +0000
+++ src/debugger/debugger_communicator.h 2011-12-13 11:51:46 +0000
@@ -28,7 +28,7 @@
namespace zorba {
class TCPSocket;
-class socket_streambuf;
+class SocketStreambuf;
class DebuggerCommunicator {
@@ -96,13 +96,13 @@
TCPSocket* theSocket;
- socket_streambuf* theSocketInStream;
- socket_streambuf* theSocketOutStream;
+ SocketStreambuf* theSocketInStream;
+ SocketStreambuf* theSocketOutStream;
std::istream* theCommunicatorInStream;
std::ostream* theCommunicatorOutStream;
ResponseQueue* theResponseQueue;
};
-}//end of namespace
+} //namespace zorba
#endif // ZORBA_DEBUGGER_COMMUNICATOR_H
=== modified file 'src/debugger/debugger_protocol.cpp'
--- src/debugger/debugger_protocol.cpp 2011-06-22 11:19:07 +0000
+++ src/debugger/debugger_protocol.cpp 2011-12-13 11:51:46 +0000
@@ -28,25 +28,17 @@
DebuggerCommand::DebuggerCommand(std::string& aCommand)
: theData()
{
+ // this implements the DBGP command specification:
+ // http://xdebug.org/docs-dbgp.php#ide-to-debugger-engine-communications
+
+ // the debugger client should only send space delimited command
+ // and arguments, therefore we only check for space character
std::size_t lNameEnd = aCommand.find(" ");
+
+ // first whitespace delimited token is the command name
theName = aCommand.substr(0, lNameEnd);
- std::size_t lDataBegin = aCommand.find("--", lNameEnd);
- std::string lArgs = aCommand.substr(lNameEnd + 1, lDataBegin);
- if (lDataBegin != std::string::npos) {
- lDataBegin += 2;
- while (lDataBegin < aCommand.size()) {
- switch (aCommand.at(lDataBegin)) {
- case ' ':
- case '\t':
- ++lDataBegin;
- continue;
- default:
- theData = aCommand.substr(lDataBegin);
- lDataBegin = aCommand.size();
- }
- }
- }
+ std::string lArgs = aCommand.substr(lNameEnd + 1);
bool lFollowsArg = true;
bool lInArgName = false;
@@ -74,6 +66,26 @@
lInArgName = true;
continue;
}
+ // we found the encoded data in this message
+ if (lArgName.str() == "") {
+ // DBGP is fuzzy here: can there be whitespaces between "--" and the encoded data?
+ // so, tollerate the whitespaces before data starts
+ std::string::size_type lDataBegin = i + 1;
+ while (++i < lArgs.size()) {
+ switch (lArgs.at(i)) {
+ case ' ':
+ case '\t':
+ continue;
+ default:
+ lDataBegin = i;
+ // force the while to terminate
+ i = lArgs.size();
+ }
+ }
+
+ theData = lArgs.substr(lDataBegin);
+ }
+
default:
if (!lInArgName) {
throw "error reading command";
=== modified file 'src/debugger/debugger_runtime.cpp'
--- src/debugger/debugger_runtime.cpp 2011-08-03 02:26:53 +0000
+++ src/debugger/debugger_runtime.cpp 2011-12-13 11:51:46 +0000
@@ -21,6 +21,7 @@
#include <memory>
#include <vector>
#include <sstream>
+#include <iomanip>
#include <fstream>
#include <zorba/util/uri.h>
@@ -70,7 +71,8 @@
thePlanIsOpen(false),
theSerializer(0),
theItemHandler(aHandler),
- theCallbackData(aCallBackData)
+ theCallbackData(aCallBackData),
+ theLastContinuationCommand()
{
}
@@ -122,7 +124,7 @@
DebuggerRuntime::runQuery()
{
theLock.wlock();
- theExecStatus = theExecStatus == QUERY_SUSPENDED ? QUERY_RESUMED : QUERY_RUNNING;
+ theExecStatus = QUERY_RUNNING;
try {
DebuggerCommons* lCommons = getDebbugerCommons();
@@ -144,33 +146,23 @@
theOStream.flush();
} catch (FlowCtlException&) {
// Runtime correctly terminated by user interrupt
- } catch (ZorbaException const& e){
- // this does not rethrow but only print the error message
- ZorbaImpl::notifyError(theQuery->theDiagnosticHandler, e);
+ } catch (ZorbaException const& e) {
+ std::cerr << e << std::endl;
}
theLock.wlock();
theExecStatus = QUERY_TERMINATED;
theLock.unlock();
}
-
-void
-DebuggerRuntime::setQueryRunning()
-{
- AutoLock lLock(theLock, Lock::WRITE);
- assert(theExecStatus == QUERY_RESUMED);
- theExecStatus = QUERY_RUNNING;
-}
-
// ****************************************************************************
// Breakpoints
unsigned int
-DebuggerRuntime::addBreakpoint(const QueryLoc& aLocation, bool aEnabled)
+DebuggerRuntime::addBreakpoint(String& aFileName, int aLine, bool aEnabled)
{
AutoLock lLock(theLock, Lock::WRITE);
DebuggerCommons* lCommons = getDebbugerCommons();
- return lCommons->addBreakpoint(aLocation, aEnabled);
+ return lCommons->addBreakpoint(aFileName, aLine, aEnabled);
}
Breakable
@@ -181,6 +173,13 @@
return lCommons->getBreakpoint(aId);
}
+BreakableVector
+DebuggerRuntime::getBreakpoints()
+{
+ AutoLock lLock(theLock, Lock::WRITE);
+ return getDebbugerCommons()->getBreakpoints();
+}
+
void
DebuggerRuntime::updateBreakpoint(
unsigned int aId,
@@ -219,6 +218,12 @@
std::vector<StackFrameImpl>
DebuggerRuntime::getStackFrames()
{
+ // this is only working while execution is suspended
+ if (theExecStatus != QUERY_SUSPENDED) {
+ std::string lMessage("I can only show a stack if the execution is suspended.");
+ throw lMessage;
+ }
+
std::vector<StackFrameImpl> lFrames;
DebuggerCommons* lCommons = getDebbugerCommons();
@@ -230,10 +235,8 @@
// add the frames for each function call
for (std::size_t i = 0 ; i < lRawFrames.size(); i++) {
lLocation = lRawFrames.at(i).first;
-
StackFrameImpl lFrame(lSignature, lLocation);
lFrames.push_back(lFrame);
-
lSignature = lRawFrames.at(i).second;
}
@@ -256,9 +259,35 @@
theExecStatus = QUERY_SUSPENDED;
std::stringstream lResponse;
- lResponse << "<response command=\"" << "" << "\" transaction_id=\"" << theLastContinuationTransactionID << "\" ";
- lResponse << "reason=\"ok\" status=\"break\" ";
- lResponse << "/>";
+ lResponse << "<response "
+ << "command=\"" << theLastContinuationCommand.second << "\" "
+ << "transaction_id=\"" << theLastContinuationCommand.first << "\" "
+ << "reason=\"ok\" status=\"break\" "
+ << ">";
+
+ // if available, show the location where the execution is suspended
+ // this should be the top-most stack frame
+ std::vector<StackFrameImpl> lFrames = getStackFrames();
+ if (lFrames.size() > 0) {
+ // wrap in CDATA because xml elements might come along
+ lResponse << "<![CDATA[";
+
+ StackFrameImpl lFrame = lFrames[lFrames.size() - 1];
+ unsigned int lBeginLine = lFrame.getLocation().getLineBegin();
+ unsigned int lEndLine = lFrame.getLocation().getLineEnd();
+ String lFileName = lFrame.getLocation().getFileName();
+ lResponse << lFrame.getSignature()
+ << " at " << lFileName
+ << ":" << lBeginLine;
+
+ // show also the current line
+ lResponse << std::endl << std::endl;
+ lResponse << listSource(lFileName, lBeginLine, lEndLine, true);
+
+ lResponse << "]]>";
+ }
+
+ lResponse << "</response>";
theCommunicator->send(lResponse.str());
theLock.unlock();
@@ -267,9 +296,24 @@
void
+DebuggerRuntime::startRuntime()
+{
+ AutoLock lLock(theLock, Lock::WRITE);
+ if (theExecStatus == QUERY_RUNNING) {
+ return;
+ }
+ theExecStatus = QUERY_RUNNING;
+ start();
+}
+
+
+void
DebuggerRuntime::resumeRuntime()
{
AutoLock lLock(theLock, Lock::WRITE);
+ if (theExecStatus != QUERY_SUSPENDED) {
+ return;
+ }
theExecStatus = QUERY_RUNNING;
resume();
}
@@ -282,10 +326,10 @@
theExecStatus = QUERY_TERMINATED;
std::stringstream lResult;
- lResult << "<response command=\"stop\" "
+ lResult << "<response command=\"" << theLastContinuationCommand.second << "\" "
<< "status=\"stopping\" "
<< "reason=\"ok\" "
- << "transaction_id=\"" << theLastContinuationTransactionID << "\">"
+ << "transaction_id=\"" << theLastContinuationCommand.first << "\">"
<< "</response>";
theCommunicator->send(lResult.str());
// TODO: something more here?
@@ -302,6 +346,30 @@
std::vector<std::pair<std::string, std::string> >
+DebuggerRuntime::getVariables()
+{
+ std::vector<std::pair<std::string, std::string> > lVarResult;
+
+ std::vector<std::pair<std::string, std::string> > lVarTmp;
+ std::vector<std::pair<std::string, std::string> >::iterator lIter;
+
+ // get the locals and add them to result
+ lVarTmp = getVariables(true);
+ for (lIter = lVarTmp.begin(); lIter != lVarTmp.end(); lIter++) {
+ lVarResult.push_back(*lIter);
+ }
+
+ // get the globals and add them to result
+ lVarTmp = getVariables(false);
+ for (lIter = lVarTmp.begin(); lIter != lVarTmp.end(); lIter++) {
+ lVarResult.push_back(*lIter);
+ }
+
+ return lVarResult;
+};
+
+
+std::vector<std::pair<std::string, std::string> >
DebuggerRuntime::getVariables(bool aLocals)
{
DebuggerCommons* lCommons = getDebbugerCommons();
@@ -392,26 +460,46 @@
void
-DebuggerRuntime::step(StepCommand aStepType)
-{
- DebuggerCommons* lCommons = theWrapper->thePlanState->theDebuggerCommons;
-
- switch (aStepType)
- {
- case STEP_INTO:
- // Resume and then suspend as soon as the next iterator is reached.
- lCommons->setBreak(true, CAUSE_STEP);
- resumeRuntime();
- break;
- case STEP_OUT:
- lCommons->makeStepOut();
- resumeRuntime();
- break;
- case STEP_OVER:
- lCommons->makeStepOver();
- resumeRuntime();
- break;
- }
+DebuggerRuntime::stepIn()
+{
+ DebuggerCommons* lCommons = theWrapper->thePlanState->theDebuggerCommons;
+ // Resume and then suspend as soon as the next iterator is reached.
+ lCommons->setBreak(true, CAUSE_STEP);
+
+ if (theExecStatus == QUERY_SUSPENDED) {
+ resumeRuntime();
+ } else {
+ startRuntime();
+ }
+}
+
+
+void
+DebuggerRuntime::stepOver()
+{
+ DebuggerCommons* lCommons = theWrapper->thePlanState->theDebuggerCommons;
+ lCommons->makeStepOver();
+
+ if (theExecStatus == QUERY_SUSPENDED) {
+ resumeRuntime();
+ } else {
+ startRuntime();
+ }
+}
+
+
+void
+DebuggerRuntime::stepOut()
+{
+ // this combination doesn't make sense: to step out when the exeecution did not start yet
+ if (theExecStatus != QUERY_SUSPENDED) {
+ return;
+ }
+
+ DebuggerCommons* lCommons = theWrapper->thePlanState->theDebuggerCommons;
+ lCommons->makeStepOut();
+
+ resumeRuntime();
}
@@ -425,6 +513,13 @@
std::list<std::pair<zstring, zstring> >
DebuggerRuntime::eval(zstring& aExpr)
{
+ // must check if we actually CAN eval (only while in "break" status)
+ if (theExecStatus != QUERY_SUSPENDED) {
+ std::string lMessage("I can only eval expressions if the execution is suspended.");
+ throw lMessage;
+ }
+
+
// disable the xml declaration for evals/variables
Zorba_omit_xml_declaration_t lOldOpt = theSerializerOptions.omit_xml_declaration;
theSerializerOptions.omit_xml_declaration = ZORBA_OMIT_XML_DECLARATION_YES;
@@ -446,55 +541,181 @@
std::string
-DebuggerRuntime::listSource()
+DebuggerRuntime::listSource(
+ String& lFileName,
+ unsigned int aBeginLine,
+ unsigned int aEndLine,
+ bool aZorbaExtensions)
{
- //ZORBA_ASSERT(dynamic_cast<ListCommand*>(theCurrentMessage));
- //ListCommand* lCommand = dynamic_cast<ListCommand*>(theCurrentMessage);
- //std::string lFile;
- //lFile = theWrapper->thePlanState->theDebuggerCommons->getFilepathOfURI(
- // lCommand->getFilename());
-
- //std::string lCurrLine;
- ////std::string::iterator lSIter;
- ////for (lSIter = lFile.begin(); lSIter != lFile.end(); ++lSIter) {
- //// if (*lSIter == '\\' && *(lSIter+1) == '\\') {
- //// lFile.erase(lSIter);
- //// ++lSIter;
- //// }
- ////}
- //std::ifstream lStream(lFile.c_str());
- //for (unsigned long i = 1; i < lCommand->getFirstline() && lStream.good(); ++i)
- //{
- // std::getline(lStream, lCurrLine);
- //}
- //std::stringstream lOut;
- //for (unsigned long i = lCommand->getFirstline();
- // i <= lCommand->getLastline() && lStream.good(); ++i) {
- // std::getline(lStream, lCurrLine);
- // lOut << lCurrLine;
- // if (lStream.good()) {
- // lOut << std::endl;
- // }
- //}
- //return new ListReply(
- // theCurrentMessage->getId(), DEBUGGER_NO_ERROR, lOut.str());
-
- return "";
+ // these are needed if extensions are enabled
+ String lFileUri;
+ unsigned int lCurrentLine = 0;
+
+ // for unspecified files determine the file
+ if (lFileName == "") {
+ // if not started, than it's the main module
+ if (theExecStatus != QUERY_SUSPENDED) {
+#ifdef WIN32
+ lFileName = theQuery->getFileName();
+#else
+ // TODO: under Linux, when trying to get the file name of the query
+ // the call fails because getFileName tries to get a lock that
+ // is already taken. Therefore the assertion in mutex.cpp:63
+ // terminates the execution
+ lFileName = "";
+#endif
+ }
+ // else, the file pointed by the top-most stack frame
+ else {
+ std::vector<StackFrameImpl> lRawFrames = getStackFrames();
+ StackFrameImpl lFrame = lRawFrames.at(lRawFrames.size() - 1);
+ lFileName = lFrame.getLocation().getFileName();
+ // filter out the eval stack frames. They Start with "eval@"
+ // TODO: Unsafe if the stackframe changes notation.
+ // Should use a constant taken from the stack frame logic.
+ if (lFileName.substr(0, 5) == "eval@") {
+ // TODO: can we get the eval iterator, get its source and surprize the user
+ // with the source code of the eval code. That would be great!
+ std::stringstream lSs;
+ lSs << "Cannot list source code for stack frames inside an eval expression. "
+ << "(Yet! Try again in the next version!)";
+ throw lSs.str();
+ }
+ lCurrentLine = lFrame.getLocation().getLineBegin();
+ }
+ }
+
+#ifdef WIN32
+ // TODO: tolower all the file names/URIs on Windows
+ // This must be implemented also in the breakable/breakpoint logic
+#endif
+
+ // normalize file uri and file name
+ String lPrefix = lFileName.substr(0, 7);
+ if (lPrefix == "file://") {
+ lFileName = URIHelper::decodeFileURI(lFileName);
+ lFileUri = URIHelper::encodeFileURI(lFileName);
+ } else {
+ if (lPrefix != "http://" && lPrefix != "https:/") {
+ lFileUri = URIHelper::encodeFileURI(lFileName);
+ } else {
+ lFileUri = lFileName;
+ }
+ }
+
+ // check if this file is actually one file where breakpoints are allowed
+ // this prevents the user opening random files in the system
+ BreakableVector lBkps = getBreakpoints();
+ bool lFoundFile = false;
+ for (BreakableVector::size_type j = 0; j < lBkps.size(); j++) {
+ Breakable lBkp = lBkps.at(j);
+ if (lBkp.getLocation().getFilename().str() == lFileUri.str()) {
+ lFoundFile = true;
+ break;
+ }
+ }
+
+ // TODO: if lZorbaExtensions and file not found add search capability like
+ // for breakpoints. This ways the useer can specify only a file name suffix
+
+ if (!lFoundFile) {
+ std::stringstream lSs;
+ lSs << "Cannot open file: " << lFileUri;
+ throw lSs.str();
+ }
+
+ // if a file is given check if this is the one in the top-most stack frame
+ if (lCurrentLine == 0 && aZorbaExtensions && theExecStatus == QUERY_SUSPENDED) {
+ std::vector<StackFrameImpl> lRawFrames = getStackFrames();
+ StackFrameImpl lFrame = lRawFrames.at(lRawFrames.size() - 1);
+ if (lFileUri == lFrame.getLocation().getFileName()) {
+ lCurrentLine = lFrame.getLocation().getLineBegin();
+ }
+ }
+
+
+ // read the entire file
+ std::ifstream lStream(lFileName.c_str());
+ std::string lCurrLine;
+ std::vector<std::string> lFileContent;
+
+ while (lStream.good()) {
+ std::getline(lStream, lCurrLine);
+ lFileContent.push_back(lCurrLine);
+ }
+ unsigned int lLineCount = lFileContent.size();
+
+ // ocmpute the begin and end lines depending on the current line:
+ // - 5 lines before and after the current line if available
+ // - all the file otherwise
+ unsigned int lLines = 5;
+ unsigned int lClBl = lCurrentLine == 0 || lCurrentLine <= lLines ? 1 : lCurrentLine - lLines;
+ unsigned int lClEl = lCurrentLine == 0 || lCurrentLine >= lLineCount - lLines ? lLineCount : lCurrentLine + lLines;
+ aBeginLine = std::min(lLineCount, (aBeginLine == 0 ? lClBl : aBeginLine));
+ aEndLine = std::min(lLineCount, (aEndLine == 0 ? lClEl : aEndLine));
+
+ // first, find the breakpoints in this file
+ std::map<int, bool> lBreakLines;
+ if (aBeginLine <= aEndLine) {
+ for (BreakableVector::size_type j = 0; j < lBkps.size(); j++) {
+ Breakable lBkp = lBkps.at(j);
+ if (lBkp.isSet() && lBkp.getLocation().getFilename().str() == lFileUri.str()) {
+ // TODO: one could also check if the line in in the range we want
+ lBreakLines[lBkp.getLocation().getLineBegin()] = lBkp.isEnabled();
+ }
+ }
+ }
+
+ // get only the needed lines
+ std::stringstream lOut;
+ for (unsigned int i = aBeginLine; i <= aEndLine; i++) {
+ if (aZorbaExtensions) {
+ // get the width of the line number column
+ std::stringstream lTmpSs;
+ lTmpSs << aEndLine;
+ int lWidth = lTmpSs.str().length();
+
+ // prepend line info column to the source
+ lOut << std::setw(lWidth) << i << " ";
+ std::map<int, bool>::iterator lIter = lBreakLines.find(i);
+ if (lIter != lBreakLines.end()) {
+ lOut << (lIter->second ? "o" : "x");
+ } else {
+ lOut << " ";
+ }
+ lOut << (lCurrentLine == i ? ">" : "|") << " ";
+ }
+ lOut << lFileContent.at(i - 1);
+ if (i != aEndLine) {
+ lOut << std::endl;
+ }
+ }
+
+ return lOut.str();
}
void
-DebuggerRuntime::setTheLastContinuationTransactionID(int aTID)
-{
- theLastContinuationTransactionID = aTID;
-}
-
-
-int
-DebuggerRuntime::getTheLastContinuationTransactionID()
-{
- return theLastContinuationTransactionID;
-}
+DebuggerRuntime::setLastContinuationCommand(int aTransactionID, std::string aCommandName)
+{
+ theLastContinuationCommand = std::pair<int, std::string>(aTransactionID, aCommandName);
+}
+
+DebuggerRuntime*
+DebuggerRuntime::clone()
+{
+ DebuggerRuntime* lNewRuntime = new DebuggerRuntime(
+ theQuery,
+ theOStream,
+ theSerializerOptions,
+ theCommunicator,
+ theItemHandler,
+ theCallbackData);
+
+ lNewRuntime->theBreakpoints = theBreakpoints;
+ return lNewRuntime;
+}
+
// ****************************************************************************
// Private functions
=== modified file 'src/debugger/debugger_runtime.h'
--- src/debugger/debugger_runtime.h 2011-06-22 11:19:07 +0000
+++ src/debugger/debugger_runtime.h 2011-12-13 11:51:46 +0000
@@ -67,9 +67,6 @@
public:
void
- setQueryRunning();
-
- void
setNotSendTerminateEvent();
void
@@ -85,11 +82,14 @@
// Breakpints
unsigned int
- addBreakpoint(const QueryLoc& location, bool enabled);
+ addBreakpoint(String& aFileName, int aLine, bool enabled);
Breakable
getBreakpoint(unsigned int id);
+ BreakableVector
+ getBreakpoints();
+
void
updateBreakpoint(
unsigned int id,
@@ -113,13 +113,17 @@
// Other
void
- setTheLastContinuationTransactionID(int transactionID);
-
- int
- getTheLastContinuationTransactionID();
+ setLastContinuationCommand(int transactionID, std::string commandName);
std::string
- listSource();
+ listSource(
+ String& fleName,
+ unsigned int beginLine,
+ unsigned int endLine,
+ bool zorbaExtensions);
+
+ std::vector<std::pair<std::string, std::string> >
+ getVariables();
std::vector<std::pair<std::string, std::string> >
getVariables(bool locals);
@@ -130,15 +134,28 @@
void runQuery();
void
+ startRuntime();
+
+ void
resumeRuntime();
-
+
void
terminateRuntime();
void
detachRuntime();
- void step(StepCommand stepType);
+ void
+ stepIn();
+
+ void
+ stepOver();
+
+ void
+ stepOut();
+
+ DebuggerRuntime*
+ clone();
private:
@@ -162,7 +179,7 @@
itemHandler theItemHandler;
void* theCallbackData;
- int theLastContinuationTransactionID;
+ std::pair<int, std::string> theLastContinuationCommand;
};
}
=== modified file 'src/debugger/debugger_server.cpp'
--- src/debugger/debugger_server.cpp 2011-07-01 16:07:54 +0000
+++ src/debugger/debugger_server.cpp 2011-12-13 11:51:46 +0000
@@ -42,11 +42,21 @@
void* aCallbackData,
const std::string& aHost,
unsigned short aPort)
+ : theStopping(false)
{
theCommunicator = new DebuggerCommunicator(aHost, aPort);
theRuntime = new DebuggerRuntime(
aQuery, aOstream, aSerializerOptions,
theCommunicator, aHandler, aCallbackData);
+#ifdef WIN32
+ theFileName = aQuery->getFileName().str();
+#else
+ // TODO: under Linux, when trying to get the file name of the query
+ // the call fails because getFileName tries to get a lock that
+ // is already taken. Therefore the assertion in mutex.cpp:63
+ // terminates the execution
+ theFileName = "";
+#endif
}
@@ -56,7 +66,6 @@
delete theCommunicator;
}
-
bool
DebuggerServer::run()
{
@@ -70,12 +79,27 @@
std::string lCommand;
- while (theRuntime->getExecutionStatus() != QUERY_TERMINATED &&
+ while (!theStopping &&
theRuntime->getExecutionStatus() != QUERY_DETACHED) {
+
// read next command
theCommunicator->receive(lCommand);
DebuggerCommand lCmd = DebuggerCommand(lCommand);
+ if (theRuntime->getExecutionStatus() == QUERY_TERMINATED) {
+ // clone the existing runtime
+ DebuggerRuntime* lNewRuntime = theRuntime->clone();
+
+ // reset and delete the existing runtime
+ theRuntime->terminate();
+ theRuntime->resetRuntime();
+ theRuntime->join();
+ delete theRuntime;
+
+ // and save the new runtime
+ theRuntime = lNewRuntime;
+ }
+
// process the received command
std::string lResponse = processCommand(lCmd);
if (lResponse != "") {
@@ -102,8 +126,17 @@
if (!getEnvVar("DBGP_SESSION", lSession)) {
lSession = "";
}
+ ThreadId tid = Runnable::self();
std::stringstream lInitMsg;
- lInitMsg << "<init appid=\"zorba\" idekey=\"" << lIdeKey << "\" session=\"" + lSession + "\" thread=\"6666\" parent=\"zorba\" language=\"xquery\" protocol_version=\"1.0\" fileuri=\"file://D:/mm.xq\"/>";
+ lInitMsg << "<init appid=\"zorba\" "
+ << "idekey=\"" << lIdeKey << "\" "
+ << "session=\"" + lSession + "\" "
+ << "thread=\"" << tid <<"\" "
+ << "parent=\"zorba\" "
+ << "language=\"XQuery\" "
+ << "protocol_version=\"1.0\" "
+ << "fileuri=\"" << URIHelper::encodeFileURI(theFileName).str() << "\"/>";
+
theCommunicator->send(lInitMsg.str());
}
@@ -113,12 +146,20 @@
{
std::stringstream lResponse;
int lTransactionID;
+ bool lZorbaExtensions = false;
ExecutionStatus lStatus;
if (aCommand.getArg("i", lTransactionID)) {
lResponse << "<response command=\"" << aCommand.getName() << "\" transaction_id=\"" << lTransactionID << "\" ";
lStatus = theRuntime->getExecutionStatus();
+ int lExtOpt;
+ if (aCommand.getArg("z", lExtOpt)) {
+ if (lExtOpt) {
+ lZorbaExtensions = true;
+ }
+ }
+
std::string lCmdName = aCommand.getName();
switch (lCmdName.at(0)) {
@@ -132,59 +173,52 @@
if (aCommand.getArg("d", lBID)) {
try {
Breakable lBkp = theRuntime->getBreakpoint(lBID);
- std::string lFilename = lBkp.getLocation().getFilename().str();
- lFilename = URIHelper::encodeFileURI(lFilename).str();
-
- lResponse << "<breakpoint "
- << "id=\"" << lBID << "\" "
- << "type=\"line\" "
- << "state=\"" << (lBkp.isEnabled() ? "enabled" : "disabled") << "\" "
- << "filename=\"" << lFilename << "\" "
- << "lineno=\"" << lBkp.getLocation().getLineBegin() << "\" "
-// << "function=\"FUNCTION\" "
-// << "exception=\"EXCEPTION\" "
-// << "hit_value=\"HIT_VALUE\" "
-// << "hit_condition=\"HIT_CONDITION\" "
-// << "hit_count=\"HIT_COUNT\" "
- << ">"
-// << "<expression>EXPRESSION</expression>"
- << "</breakpoint>";
-
+ buildBreakpoint(lBkp, lBID, lResponse);
} catch (std::string& lErr) {
- return buildErrorResponse(lTransactionID, lCmdName, 4, lErr);
+ return buildErrorResponse(lTransactionID, lCmdName, 205, lErr);
}
} else {
// error
}
} else {
// breakpoint_list
+ BreakableVector lBkps = theRuntime->getBreakpoints();
+
+ BreakableVector::iterator lIter = lBkps.begin();
+ int lId = -1;
+ while (lIter != lBkps.end()) {
+ Breakable lBkp = *(lIter++);
+ lId++;
+
+ // this is only a location without a breakpoint set by the user
+ if (!lBkp.isSet()) {
+ continue;
+ }
+
+ buildBreakpoint(lBkp, lId, lResponse);
+ }
}
} else {
if (aCommand.getName() == "breakpoint_set") {
int lLineNo;
aCommand.getArg("n", lLineNo);
- std::string lFileName;
- aCommand.getArg("f", lFileName);
+ std::string lFileNameTmp;
+ aCommand.getArg("f", lFileNameTmp);
+ String lFileName(lFileNameTmp);
+
std::string lState;
+ bool lEnabled = true;
if (!aCommand.getArg("s", lState)) {
lState = "enabled";
}
-
- if (lFileName.substr(0, 7) == "file://") {
- lFileName = URIHelper::decodeFileURI(lFileName).str();
- }
-
- QueryLoc lLocation;
- lLocation.setLineBegin(lLineNo);
- lLocation.setLineEnd(lLineNo);
- lLocation.setFilename(lFileName);
+ lEnabled = (lState == "disabled" ? false : true);
+ lState = (lEnabled ? "enabled" : "disabled");
try {
- bool lEnabled = (lState == "disabled" ? false : true);
- unsigned int lBID = theRuntime->addBreakpoint(lLocation, lEnabled);
- lResponse << "state=\"enabled\" id=\"" << lBID << "\" ";
- } catch (std::string lErr) {
+ unsigned int lBID = theRuntime->addBreakpoint(lFileName, lLineNo, lEnabled);
+ lResponse << "state=\"" << lState << "\" id=\"" << lBID << "\" ";
+ } catch (std::string& lErr) {
return buildErrorResponse(lTransactionID, lCmdName, 200, lErr);
}
@@ -196,11 +230,14 @@
int lHitValue;
// bool lHasCondition = false;
- // we can not change the line number of a breakpoint
- // so we will never read the -n option
+ // since we can not change the line number of a breakpoint, we throw an error for that
+ if (aCommand.getArg("n", lBID)) {
+ return buildErrorResponse(lTransactionID, lCmdName, 208, "A breakpoint line number can not be changed. Omit the -n argument.");
+ }
+ // the breakpoint ID must be present or we throw an error
if (!aCommand.getArg("d", lBID)) {
- // TODO: throw exception
+ return buildErrorResponse(lTransactionID, lCmdName, 200, "No breakpoint could not be updated: missing breakpoint ID (-d) argument.");
}
if (!aCommand.getArg("s", lState)) {
lState = "enabled";
@@ -216,14 +253,18 @@
try {
bool lEnabled = (lState == "disabled" ? false : true);
theRuntime->updateBreakpoint(lBID, lEnabled, lCondition, lHitValue);
- } catch (std::string lErr) {
- // TODO: report error
+ } catch (std::string& lErr) {
+ return buildErrorResponse(lTransactionID, lCmdName, 205, lErr);
}
} else if (aCommand.getName() == "breakpoint_remove") {
int lBID;
if (aCommand.getArg("d", lBID)) {
- theRuntime->removeBreakpoint(lBID);
+ try {
+ theRuntime->removeBreakpoint(lBID);
+ } catch (std::string& lErr) {
+ return buildErrorResponse(lTransactionID, lCmdName, 205, lErr);
+ }
}
}
@@ -253,13 +294,30 @@
if (!aCommand.getArg("c", lContextID)) {
lContextID = 0;
}
+ // we allow -1 to return the properties (variables) in all contexts
+ if (lContextID < -1 || lContextID > 1) {
+ std::stringstream lErrMsg;
+ lErrMsg << "Context invalid (" << lContextID << ") invalid. Check the context list for a correct ID.";
+ return buildErrorResponse(lTransactionID, lCmdName, 302, lErrMsg.str());
+ }
// currently we only support contexts for the topmost stack frame
if (lContextDepth == 0) {
- // get the variables either local or global depenging on the context ID
- std::vector<std::pair<std::string, std::string> > lVariables =
- theRuntime->getVariables(lContextID == 0 ? true : false);
+ // get the variables depenging on the context ID (all, local, global)
+ std::vector<std::pair<std::string, std::string> > lVariables;
+ switch (lContextID) {
+ case -1:
+ lVariables = theRuntime->getVariables();
+ break;
+ case 0:
+ lVariables = theRuntime->getVariables(true);
+ break;
+ case 1:
+ lVariables = theRuntime->getVariables(false);
+ break;
+ }
+
std::vector<std::pair<std::string, std::string> >::iterator lIter =
lVariables.begin();
@@ -269,7 +327,17 @@
std::string lName = getVariableName(lFullName);
buildProperty(lFullName, lName, lIter->second, lResponse);
}
+ } else {
+ std::stringstream lErrMsg;
+ if (lContextDepth < 0) {
+ lErrMsg << "Invalid stack depth: " << lContextDepth << "";
+ return buildErrorResponse(lTransactionID, lCmdName, 301, lErrMsg.str());
+ } else if (lContextDepth > 0) {
+ lErrMsg << "Invalid stack depth: " << lContextDepth << ". Currently we only support data commands for the top-most stack frame.";
+ return buildErrorResponse(lTransactionID, lCmdName, 301, lErrMsg.str());
+ }
}
+
}
break;
@@ -290,6 +358,8 @@
std::string lName = "";
buildChildProperties(lName, lResults, lResponse);
+ } catch (std::string aMessage) {
+ return buildErrorResponse(lTransactionID, lCmdName, 206, aMessage);
} catch (...) {
return buildErrorResponse(lTransactionID, lCmdName, 206, "Error while evaluating expression.");
}
@@ -358,9 +428,9 @@
// run
case 'r':
- if (lStatus == QUERY_SUSPENDED || lStatus == QUERY_IDLE) {
- theRuntime->setTheLastContinuationTransactionID(lTransactionID);
- if (lStatus == QUERY_IDLE) {
+ if (lStatus == QUERY_SUSPENDED || lStatus == QUERY_IDLE || lStatus == QUERY_TERMINATED) {
+ theRuntime->setLastContinuationCommand(lTransactionID, aCommand.getName());
+ if (lStatus == QUERY_IDLE || lStatus == QUERY_TERMINATED) {
theRuntime->start();
} else if (lStatus == QUERY_SUSPENDED) {
theRuntime->resumeRuntime();
@@ -374,9 +444,36 @@
// stack_depth, stack_get, status, stop, step_into, step_over, step_out
case 's':
- if (aCommand.getName() == "stop") {
-
- theRuntime->setTheLastContinuationTransactionID(lTransactionID);
+ if (aCommand.getName() == "source") {
+ lResponse << "success=\"1\" ";
+ lResponse << ">";
+
+ int lBeginLine;
+ if (!aCommand.getArg("b", lBeginLine)) {
+ lBeginLine = 0;
+ }
+ int lEndLine;
+ if (!aCommand.getArg("e", lEndLine)) {
+ lEndLine = 0;
+ }
+ std::string lTmp;
+ if (!aCommand.getArg("f", lTmp)) {
+ lTmp = "";
+ }
+ String lFileName(lTmp);
+
+ // we wrap the source code in CDATA to have it unparsed because it might contain XML
+ lResponse << "<![CDATA[";
+ try {
+ lResponse << theRuntime->listSource(lFileName, lBeginLine, lEndLine, lZorbaExtensions) << std::endl;
+ } catch (std::string& lErr) {
+ return buildErrorResponse(lTransactionID, lCmdName, 100, lErr);
+ }
+ lResponse << "]]>";
+
+ } else if (aCommand.getName() == "stop") {
+ theRuntime->setLastContinuationCommand(lTransactionID, aCommand.getName());
+ theStopping = true;
lResponse << "reason=\"ok\" status=\"stopped\" ";
lResponse << ">";
@@ -389,33 +486,18 @@
} else if (aCommand.getName() == "stack_get") {
- lResponse << ">";
- std::vector<StackFrameImpl> lFrames = theRuntime->getStackFrames();
-
- std::vector<StackFrameImpl>::reverse_iterator lRevIter;
- int i = 0;
- for (lRevIter = lFrames.rbegin(); lRevIter < lFrames.rend(); ++lRevIter, ++i) {
- String lFileName(lRevIter->getLocation().getFileName());
- lFileName = URIHelper::encodeFileURI(lFileName);
- unsigned int lLB = lRevIter->getLocation().getLineBegin();
- unsigned int lLE = lRevIter->getLocation().getLineEnd();
-
- // for the client, the column numbers are 1-based
- unsigned int lCB = lRevIter->getLocation().getColumnBegin() - 1;
- // moreover, the column end points to the last character to be selected
- unsigned int lCE = lRevIter->getLocation().getColumnEnd() - 2;
-
- lResponse << "<stack "
- << "level=\"" << i << "\" "
- << "type=\"" << "file" << "\" "
- << "filename=\"" << lFileName << "\" "
- << "lineno=\"" << lLB << "\" "
- << "where=\"" << lRevIter->getSignature() << "\" "
- << "cmdbegin=\"" << lLB << ":" << lCB << "\" "
- << "cmdend=\"" << lLE << ":" << lCE << "\" "
- << "/>";
+ try {
+ lResponse << ">";
+ std::vector<StackFrameImpl> lFrames = theRuntime->getStackFrames();
+
+ std::vector<StackFrameImpl>::reverse_iterator lRevIter;
+ int i = 0;
+ for (lRevIter = lFrames.rbegin(); lRevIter < lFrames.rend(); ++lRevIter, ++i) {
+ buildStackFrame(*lRevIter, i, lResponse);
+ }
+ } catch (std::string& lErr) {
+ return buildErrorResponse(lTransactionID, lCmdName, 303, lErr);
}
-
} else if (aCommand.getName() == "status") {
ExecutionStatus lStatus = theRuntime->getExecutionStatus();
@@ -425,7 +507,6 @@
lStatusStr = "starting";
break;
case QUERY_RUNNING:
- case QUERY_RESUMED:
lStatusStr = "running";
break;
case QUERY_SUSPENDED:
@@ -442,16 +523,20 @@
<< ">";
} else if (aCommand.getName() == "step_into") {
- theRuntime->setTheLastContinuationTransactionID(lTransactionID);
- theRuntime->step(STEP_INTO);
+ theRuntime->setLastContinuationCommand(lTransactionID, aCommand.getName());
+ theRuntime->stepIn();
return "";
} else if (aCommand.getName() == "step_over") {
- theRuntime->setTheLastContinuationTransactionID(lTransactionID);
- theRuntime->step(STEP_OVER);
+ theRuntime->setLastContinuationCommand(lTransactionID, aCommand.getName());
+ theRuntime->stepOver();
return "";
} else if (aCommand.getName() == "step_out") {
- theRuntime->setTheLastContinuationTransactionID(lTransactionID);
- theRuntime->step(STEP_OUT);
+ ExecutionStatus lStatus = theRuntime->getExecutionStatus();
+ if (lStatus != QUERY_SUSPENDED) {
+ return buildErrorResponse(lTransactionID, lCmdName, 6, "Can not step out since the execution is not started.");
+ }
+ theRuntime->setLastContinuationCommand(lTransactionID, aCommand.getName());
+ theRuntime->stepOut();
return "";
}
@@ -483,6 +568,65 @@
}
void
+DebuggerServer::buildStackFrame(
+ StackFrame& aFrame,
+ int aSNo,
+ std::ostream& aStream)
+{
+ // the file names in query locations always come as URIs, so decode it
+ String lFileName(aFrame.getLocation().getFileName());
+ if (lFileName.substr(0, 7) == "file://") {
+ lFileName = URIHelper::decodeFileURI(lFileName);
+ }
+
+ unsigned int lLB = aFrame.getLocation().getLineBegin();
+ unsigned int lLE = aFrame.getLocation().getLineEnd();
+
+ // for the client, the column numbers are 1-based
+ unsigned int lCB = aFrame.getLocation().getColumnBegin() - 1;
+ // moreover, the column end points to the last character to be selected
+ unsigned int lCE = aFrame.getLocation().getColumnEnd() - 2;
+
+ aStream << "<stack "
+ << "level=\"" << aSNo << "\" "
+ << "type=\"" << "file" << "\" "
+ << "filename=\"" << lFileName << "\" "
+ << "lineno=\"" << lLB << "\" "
+ << "where=\"" << aFrame.getSignature() << "\" "
+ << "cmdbegin=\"" << lLB << ":" << lCB << "\" "
+ << "cmdend=\"" << lLE << ":" << lCE << "\" "
+ << "/>";
+};
+
+void
+DebuggerServer::buildBreakpoint(
+ Breakable& aBreakpoint,
+ int aBID,
+ std::ostream& aStream)
+{
+ // the file names in query locations always come as URIs, so decode it
+ String lFileName(aBreakpoint.getLocation().getFilename().str());
+ if (lFileName.substr(0, 7) == "file://") {
+ lFileName = URIHelper::decodeFileURI(lFileName);
+ }
+
+ aStream << "<breakpoint "
+ << "id=\"" << aBID << "\" "
+ << "type=\"line\" "
+ << "state=\"" << (aBreakpoint.isEnabled() ? "enabled" : "disabled") << "\" "
+ << "filename=\"" << lFileName << "\" "
+ << "lineno=\"" << aBreakpoint.getLocation().getLineBegin() << "\" "
+// << "function=\"FUNCTION\" "
+// << "exception=\"EXCEPTION\" "
+// << "hit_value=\"HIT_VALUE\" "
+// << "hit_condition=\"HIT_CONDITION\" "
+// << "hit_count=\"HIT_COUNT\" "
+ << ">"
+// << "<expression>EXPRESSION</expression>"
+ << "</breakpoint>";
+};
+
+void
DebuggerServer::buildProperty(
std::string& aFullName,
std::string& aName,
=== modified file 'src/debugger/debugger_server.h'
--- src/debugger/debugger_server.h 2011-07-01 16:07:54 +0000
+++ src/debugger/debugger_server.h 2011-12-13 11:51:46 +0000
@@ -23,6 +23,7 @@
#include "zorbatypes/zstring.h"
#include "debugger_common.h"
+#include "debugger_commons.h"
#include "debugger_protocol.h"
@@ -72,6 +73,18 @@
getVariableName(std::string& aFullName);
void
+ buildStackFrame(
+ StackFrame& frame,
+ int stackFrameNumber,
+ std::ostream& stream);
+
+ void
+ buildBreakpoint(
+ Breakable& breakpoint,
+ int breakpointID,
+ std::ostream& stream);
+
+ void
buildProperty(
std::string& fullName,
std::string& name,
@@ -94,7 +107,8 @@
DebuggerCommunicator* theCommunicator;
DebuggerRuntime* theRuntime;
-
+ std::string theFileName;
+ bool theStopping;
};
}
=== modified file 'src/debugger/socket_streambuf.cpp'
--- src/debugger/socket_streambuf.cpp 2011-07-01 01:53:24 +0000
+++ src/debugger/socket_streambuf.cpp 2011-12-13 11:51:46 +0000
@@ -14,66 +14,79 @@
* limitations under the License.
*/
#include "stdafx.h"
+
+#include "socket_streambuf.h"
+
#include <sstream>
#include <cstring>
#include <iostream>
-#include "socket_streambuf.h"
+
namespace zorba {
- static const int BUF_SIZE = 1024;
+static const int BUF_SIZE = 1024;
- socket_streambuf::socket_streambuf(TCPSocket& aSocket)
+SocketStreambuf::SocketStreambuf(TCPSocket& aSocket)
: theSocket(aSocket)
- {
- theInputBuffer = new char_type[BUF_SIZE];
- theOutputBuffer = new char_type[BUF_SIZE];
- setg(theInputBuffer, theInputBuffer, theInputBuffer);
- setp(theOutputBuffer, theOutputBuffer + BUF_SIZE);
- }
-
- socket_streambuf::~socket_streambuf()
- {
- delete[] theInputBuffer;
- }
-
- int socket_streambuf::sync()
- {
-#if 0
- std::cout << "sending:" << std::endl << std::string(pbase(), pptr() - pbase()) << std::endl;
-#endif
- theSocket.send(pbase(), pptr() - pbase());
- setp(theOutputBuffer, theOutputBuffer + BUF_SIZE);
- return 0;
- }
-
- int socket_streambuf::underflow() {
- int size = theSocket.recv(theInputBuffer, BUF_SIZE);
- if (size == 0)
- return EOF;
- setg(theInputBuffer, theInputBuffer, theInputBuffer + size);
- return theInputBuffer[0];
- }
-
- int socket_streambuf::overflow(int c)
- {
-#if 0
- std::cout << "sending:" << std::endl << std::string(pbase(), pptr() - pbase()) << std::endl;
-#endif
- theSocket.send(pbase(), pptr() - pbase());
- setp(theOutputBuffer, theOutputBuffer + BUF_SIZE);
- sputc(c);
- return 0;
- }
-
- DebuggerResponse::DebuggerResponse(std::istream& aStream)
- {
- }
-
- bool DebuggerResponse::isInit() const {
- std::string rootNodeName(reinterpret_cast<const char*>(theDoc->children->name));
- if (rootNodeName == "init")
- return true;
- return false;
- }
-}
+{
+ theInputBuffer = new char_type[BUF_SIZE];
+ theOutputBuffer = new char_type[BUF_SIZE];
+ setg(theInputBuffer, theInputBuffer, theInputBuffer);
+ setp(theOutputBuffer, theOutputBuffer + BUF_SIZE);
+}
+
+SocketStreambuf::~SocketStreambuf()
+{
+ delete[] theInputBuffer;
+}
+
+int
+SocketStreambuf::sync()
+{
+#if 0
+ std::cout << "sending:" << std::endl << std::string(pbase(), pptr() - pbase()) << std::endl;
+#endif
+ theSocket.send(pbase(), pptr() - pbase());
+ setp(theOutputBuffer, theOutputBuffer + BUF_SIZE);
+ return 0;
+}
+
+int
+SocketStreambuf::underflow()
+{
+ int size = theSocket.recv(theInputBuffer, BUF_SIZE);
+ if (size == 0) {
+ return EOF;
+ }
+ setg(theInputBuffer, theInputBuffer, theInputBuffer + size);
+ return theInputBuffer[0];
+}
+
+int
+SocketStreambuf::overflow(int c)
+{
+#if 0
+ std::cout << "sending:" << std::endl << std::string(pbase(), pptr() - pbase()) << std::endl;
+#endif
+ theSocket.send(pbase(), pptr() - pbase());
+ setp(theOutputBuffer, theOutputBuffer + BUF_SIZE);
+ sputc(c);
+ return 0;
+}
+
+
+DebuggerResponse::DebuggerResponse(std::istream& aStream)
+{
+}
+
+bool
+DebuggerResponse::isInit() const
+{
+ std::string rootNodeName(reinterpret_cast<const char*>(theDoc->children->name));
+ if (rootNodeName == "init") {
+ return true;
+ }
+ return false;
+}
+
+} // namespace zorba
=== modified file 'src/debugger/socket_streambuf.h'
--- src/debugger/socket_streambuf.h 2011-06-22 11:19:07 +0000
+++ src/debugger/socket_streambuf.h 2011-12-13 11:51:46 +0000
@@ -13,7 +13,10 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-#pragma once
+#ifndef ZORBA_SOCKET_STREAMBUF_H
+#define ZORBA_SOCKET_STREAMBUF_H
+
+#include <streambuf>
#include <libxml/parser.h>
#include <libxml/xmlstring.h>
@@ -22,27 +25,35 @@
namespace zorba {
- class socket_streambuf : public std::streambuf {
+class SocketStreambuf : public std::streambuf {
public:
- socket_streambuf(TCPSocket& aSocket);
- virtual ~socket_streambuf();
+ SocketStreambuf(TCPSocket& aSocket);
+ virtual ~SocketStreambuf();
+
protected:
virtual int sync();
virtual int underflow();
virtual int overflow(int c = EOF);
+
private:
TCPSocket& theSocket;
char_type* theInputBuffer;
char_type* theOutputBuffer;
- };
+};
- class DebuggerResponse {
- friend class DebuggerClientImpl;
+class DebuggerResponse {
+ friend class DebuggerClientImpl;
+
private:
DebuggerResponse(std::istream& aStream);
+
public: // API
bool isInit() const;
+
private:
xmlDocPtr theDoc;
- };
-}
+};
+
+} // namespace zorba
+
+#endif // ZORBA_SOCKET_STREAMBUF_H
=== modified file 'src/unit_tests/CMakeLists.txt'
--- src/unit_tests/CMakeLists.txt 2011-06-01 13:16:28 +0000
+++ src/unit_tests/CMakeLists.txt 2011-12-13 11:51:46 +0000
@@ -17,9 +17,3 @@
unit_tests.cpp
test_uri.cpp
)
-
-IF(ZORBA_WITH_DEBUGGER)
- LIST(APPEND UNIT_TEST_SRCS
-# test_debugger_protocol.cpp
- )
-ENDIF(ZORBA_WITH_DEBUGGER)
=== removed file 'src/unit_tests/test_debugger_protocol.cpp'
--- src/unit_tests/test_debugger_protocol.cpp 2011-08-27 14:57:52 +0000
+++ src/unit_tests/test_debugger_protocol.cpp 1970-01-01 00:00:00 +0000
@@ -1,414 +0,0 @@
-/*
- * Copyright 2006-2008 The FLWOR Foundation.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <string>
-
-#include <zorba/internal/unique_ptr.h>
-
-#include "unit_test_list.h"
-
-#include "debugger/message_factory.h"
-#include "zorbatypes/zstring.h"
-
-namespace zorba
-{
-
-
-template<class T>
-bool test_packet( AbstractMessage * aMessage )
-{
- //Cast to the concrete Message Type
- T * lMessage1 = dynamic_cast<T *> ( aMessage );
- //Ensure that the cast is correct
- if(lMessage1 == 0){ return false; }
- //Serialize and unserialize the message
- Length length;
- Byte * msg = lMessage1->serialize( length );
- AbstractMessage * lAbstractMessage = MessageFactory::buildMessage( msg, length );
- delete[] msg;
- T * lMessage2 = dynamic_cast<T *> ( lAbstractMessage );
- if(lMessage2 == 0) { return false; }
- //Ensure that both message are identical
- bool lResult = (*lMessage1) == (*lMessage2);
- if(lResult == 0) { return false; }
- delete lAbstractMessage;
- return true;
-}
-
-
-bool msgcmp( Byte * aMsg1, const char * aMsg2, unsigned int aLength )
-{
- Byte * lMsg2 = reinterpret_cast<Byte *>( const_cast< char * >( aMsg2 ) );
- return memcmp( aMsg1, lMsg2, aLength ) == 0;
-}
-
-
-class TestDebuggerSerialization
-{
-public:
- bool testReplyMessageOk();
-
- bool testReplyMessage();
-
- bool testRunMessage();
-
- bool testResumeMessage();
-
- bool testSuspendMessage();
-
- bool testTerminateMessage();
-
- bool testStepIntoMessage();
-
- bool testStepOutMessage();
-
- bool testStepOverMessage();
-
- bool testStartedEvent();
-
- bool testTerminatedEvent();
-
- bool testSuspendedEvent();
-
- bool testResumedEvent();
-
- bool testClearMessage();
-
- bool testSetMessage();
-
- bool testEvalMessage();
-
- bool testEvalEvent();
-
- bool testVariableMessage();
-};
-
-
-bool TestDebuggerSerialization::testReplyMessage()
-{
- std::cerr << "Test reply message" << std::endl;
- ReplyMessage msg( 1, DEBUGGER_ERROR_INVALID_MESSAGE_FORMAT );
- bool lResult = test_packet<ReplyMessage>( &msg );
- if(!lResult) return false;
- const char * lBinary = "\0\0\0\xb\0\0\0\1\200\0\xb";
- Length length;
- std::unique_ptr<Byte[]> lBmsg(msg.serialize(length));
- return msgcmp( lBmsg.get(), lBinary, length );
-}
-
-
-bool TestDebuggerSerialization::testReplyMessageOk()
-{
- std::cerr << "Test reply message Ok" << std::endl;
- ReplyMessage msg( 1, DEBUGGER_NO_ERROR );
- bool lResult = test_packet<ReplyMessage>( &msg );
- if(!lResult) return false;
- test_packet<ReplyMessage>( &msg );
- const char * lBinary = "\0\0\0\xb\0\0\0\1\200\0\0";
- Length length;
- std::unique_ptr<Byte[]> lBmsg(msg.serialize(length));
- return msgcmp( lBmsg.get(), lBinary, length );
-}
-
-
-bool TestDebuggerSerialization::testRunMessage()
-{
- std::cerr << "Test run message" << std::endl;
- RunMessage msg;
- bool lResult = test_packet<RunMessage>( &msg );
- if(!lResult) return false;
- const char * lBinary = "\0\0\0\xb\0\0\0\1\0\xf1\1";
- Length length;
- std::unique_ptr<Byte[]> lBmsg(msg.serialize(length));
- return msgcmp( lBmsg.get(), lBinary, length );
-}
-
-
-bool TestDebuggerSerialization::testSuspendMessage()
-{
- std::cerr << "Test suspend message" << std::endl;
- SuspendMessage msg;
- bool lResult = test_packet<SuspendMessage>( &msg );
- if(!lResult) return false;
- const char * lBinary = "\0\0\0\xb\0\0\0\2\0\xf1\2";
- Length length;
- std::unique_ptr<Byte[]> lBmsg(msg.serialize(length));
- return msgcmp( lBmsg.get(), lBinary, length );
-}
-
-
-bool TestDebuggerSerialization::testResumeMessage()
-{
- std::cerr << "Test resume message" << std::endl;
- ResumeMessage msg;
- bool lResult = test_packet<ResumeMessage>(&msg);
- if(!lResult) return false;
- const char * lBinary = "\0\0\0\xb\0\0\0\3\0\xf1\3";
- Length length;
- std::unique_ptr<Byte[]> lBmsg(msg.serialize(length));
- return msgcmp( lBmsg.get(), lBinary, length );
-}
-
-
-bool TestDebuggerSerialization::testTerminateMessage()
-{
- std::cerr << "Test terminate message" << std::endl;
- TerminateMessage msg;
- bool lResult = test_packet<TerminateMessage>( &msg );
- if(!lResult) return false;
- const char * lBinary = "\0\0\0\xb\0\0\0\4\0\xf1\4";
- Length length;
- std::unique_ptr<Byte[]> lBmsg(msg.serialize(length));
- return msgcmp(lBmsg.get(), lBinary, length);
-}
-
-
-bool TestDebuggerSerialization::testStepIntoMessage()
-{
- std::cerr << "Test step into message" << std::endl;
- StepMessage msg(STEP_INTO);
- bool lResult = test_packet<StepMessage>( &msg );
- if (!lResult) return false;
- const char* lBinary = "\0\0\0\x19\0\0\0\5\0\xf1\5{\"stepType\":1}";
- Length length;
- std::unique_ptr<Byte[]> lBmsg(msg.serialize(length));
- return msgcmp( lBmsg.get(), lBinary, length );
-}
-
-
-bool TestDebuggerSerialization::testStepOutMessage()
-{
- std::cerr << "Test step out message" << std::endl;
- StepMessage msg(STEP_OUT);
- bool lResult = test_packet<StepMessage>( &msg );
- if (!lResult) return false;
- const char* lBinary = "\0\0\0\x19\0\0\0\6\0\xf1\5{\"stepType\":2}";
- Length length;
- std::unique_ptr<Byte[]> lBmsg(msg.serialize(length));
- return msgcmp( lBmsg.get(), lBinary, length );
-}
-
-
-bool TestDebuggerSerialization::testStepOverMessage()
-{
- std::cerr << "Test step over message" << std::endl;
- StepMessage msg(STEP_OVER);
- bool lResult = test_packet<StepMessage>( &msg );
- if (!lResult) return false;
- const char* lBinary = "\0\0\0\x19\0\0\0\7\0\xf1\5{\"stepType\":3}";
- Length length;
- std::unique_ptr<Byte[]> lBmsg(msg.serialize( length ));
- return msgcmp( lBmsg.get(), lBinary, length );
-}
-
-
-bool TestDebuggerSerialization::testStartedEvent()
-{
- std::cerr << "Test started event message" << std::endl;
- StartedEvent msg;
- bool lResult = test_packet<StartedEvent>( &msg );
- if(!lResult) return false;
- const char * lBinary = "\0\0\0\xb\0\0\0\x8\0\xf8\1";
- Length length;
- std::unique_ptr<Byte[]> lBmsg(msg.serialize(length));
- return msgcmp( lBmsg.get(), lBinary, length );
-}
-
-
-bool TestDebuggerSerialization::testTerminatedEvent()
-{
- std::cerr << "Test terminated event message" << std::endl;
- TerminatedEvent msg;
- bool lResult = test_packet<TerminatedEvent>( &msg );
- if(!lResult) return false;
- const char * lBinary = "\0\0\0\xb\0\0\0\x9\0\xf8\2";
- Length length;
- std::unique_ptr<Byte[]> lBmsg(msg.serialize(length));
- return msgcmp( lBmsg.get(), lBinary, length );
-}
-
-
-bool TestDebuggerSerialization::testSuspendedEvent()
-{
- std::cerr << "Test suspended event message" << std::endl;
-
- QueryLoc loc;
- loc.setFilename( "data.xq" );
- loc.setLineBegin( 1 );
- loc.setColumnBegin( 1 );
- loc.setLineEnd( 1 );
- loc.setColumnEnd( 1 );
-
- SuspendedEvent msg( loc, CAUSE_USER );
- bool lResult =test_packet< SuspendedEvent >( &msg );
- if(!lResult) return false;
-
- Length length;
- std::unique_ptr<Byte[]> lBmsg(msg.serialize(length));
- std::unique_ptr<char[]> lBinary(new char[length]);
- memcpy( lBinary.get(), "\0\0\0\x070\0\0\0\xa\0\xf8\3", MESSAGE_HEADER_SIZE );
- const char * lJSONString = "{\"cause\":1,\"location\":{\"fileName\":\"data.xq\",\"lineBegin\":1,\"columnBegin\":1,\"lineEnd\":1,\"columnEnd\":1}}";
- memcpy( lBinary.get() + MESSAGE_HEADER_SIZE, lJSONString, length - MESSAGE_HEADER_SIZE );
- return msgcmp( lBmsg.get(), lBinary.get(), length );
-}
-
-
-bool TestDebuggerSerialization::testResumedEvent()
-{
- std::cerr << "Test resumed event message" << std::endl;
- ResumedEvent msg;
- bool lResult = test_packet<ResumedEvent>( &msg );
- if(!lResult) return false;
- const char * lBinary = "\0\0\0\xb\0\0\0\xb\0\xf8\4";
- Length length;
- std::unique_ptr<Byte[]> lBmsg(msg.serialize(length));
- return msgcmp( lBmsg.get(), lBinary, length );
-}
-
-
-bool TestDebuggerSerialization::testClearMessage()
-{
- std::cerr << "Test clear message" << std::endl;
- ClearMessage msg;
- msg.addId( 1 );
- msg.addId( 2 );
- msg.addId( 3 );
- msg.addId( 4 );
- bool lResult = test_packet<ClearMessage>( &msg );
- if(!lResult) return false;
- return true;
-}
-
-
-bool TestDebuggerSerialization::testSetMessage()
-{
- std::cerr << "Test set message" << std::endl;
- QueryLoc loc;
- loc.setFilename( "data.xq" );
- loc.setLineBegin( 1 );
- loc.setColumnBegin( 1 );
- loc.setLineEnd( 1 );
- loc.setColumnEnd( 1 );
- SetMessage msg;
- msg.addLocation( 1, loc );
- zstring lExpr("$i=1");
- msg.addExpr( 2, lExpr);
- bool lResult = test_packet<SetMessage>( &msg );
- if(!lResult) return false;
- return true;
-}
-
-
-bool TestDebuggerSerialization::testEvalMessage()
-{
- std::cerr << "Test eval message" << std::endl;
- EvalMessage msg( "$i/foo" );
- bool lResult = test_packet<EvalMessage>( &msg );
- if(!lResult) return false;
- return true;
-}
-
-
-bool TestDebuggerSerialization::testEvalEvent()
-{
- std::cerr << "Test eval event" << std::endl;
- std::list<std::pair<zstring, zstring> > lList;
- EvaluatedEvent evt(0, "()", lList);
- evt.setId(5);
- bool lResult = test_packet<EvaluatedEvent>(&evt);
- if (!lResult) return false;
- zstring lData = evt.getData();
- zstring::size_type lPos = lData.find("id");
- if (lPos == zstring::npos) {
- return false;
- }
- lPos = lData.find("5", lPos);
- if (lPos == zstring::npos) {
- return false;
- }
- if (evt.getId() != 5) {
- return false;
- }
- return true;
-}
-
-
-bool TestDebuggerSerialization::testVariableMessage()
-{
- std::cerr << "Test variable message" << std::endl;
- {
- VariableMessage msg;
- bool lResult = test_packet<VariableMessage>( &msg );
- if(!lResult) return false;
- }
- {
- VariableReply msg( 1, DEBUGGER_NO_ERROR );
- msg.addGlobal( "$i", "xs:integer" );
- msg.addGlobal( "$j", "xs:integer" );
- msg.addLocal("$foo", "xs:string" );
- msg.addLocal("$bar", "xs:string" );
- bool lResult = test_packet<VariableReply>( &msg );
- if(!lResult) return false;
- }
- return true;
-}
-
-
-
-int UnitTests::runDebuggerProtocolTest(int argc, char* argv[])
-{
- bool lResult;
- zorba::TestDebuggerSerialization * test = new zorba::TestDebuggerSerialization();
- lResult = test->testReplyMessage();
- if(!lResult) return 1;
- lResult = test->testReplyMessageOk();
- if(!lResult) return 1;
- lResult = test->testRunMessage();
- if(!lResult) return 1;
- lResult = test->testSuspendMessage();
- if(!lResult) return 1;
- lResult = test->testResumeMessage();
- if(!lResult) return 1;
- lResult = test->testTerminateMessage();
- if(!lResult) return 1;
- lResult = test->testStepIntoMessage();
- if(!lResult) return 1;
- lResult = test->testStepOutMessage();
- if(!lResult) return 1;
- lResult = test->testStepOverMessage();
- if(!lResult) return 1;
- lResult = test->testStartedEvent();
- if(!lResult) return 1;
- lResult = test->testTerminatedEvent();
- if(!lResult) return 1;
- lResult = test->testSuspendedEvent();
- if(!lResult) return 1;
- lResult = test->testResumedEvent();
- if(!lResult) return 1;
- lResult = test->testClearMessage();
- if(!lResult) return 1;
- lResult = test->testSetMessage();
- if(!lResult) return 1;
- lResult = test->testEvalMessage();
- if(!lResult) return 1;
- lResult = test->testVariableMessage();
- if(!lResult) return 1;
- delete test;
- return 0;
-}
-
-} // namespace zorba
-/* vim:set et sw=2 ts=2: */
=== added directory 'test/rbkt/ExpQueryResults/zorba/debugger'
=== added directory 'test/rbkt/ExpQueryResults/zorba/debugger/dmh'
=== added file 'test/rbkt/ExpQueryResults/zorba/debugger/dmh/break_response.xml.res'
--- test/rbkt/ExpQueryResults/zorba/debugger/dmh/break_response.xml.res 1970-01-01 00:00:00 +0000
+++ test/rbkt/ExpQueryResults/zorba/debugger/dmh/break_response.xml.res 2011-12-13 11:51:46 +0000
@@ -0,0 +1,1 @@
+5 break in dmh:process#1 at file.xq:10
\ No newline at end of file
=== added file 'test/rbkt/ExpQueryResults/zorba/debugger/dmh/break_response_no_info.xml.res'
--- test/rbkt/ExpQueryResults/zorba/debugger/dmh/break_response_no_info.xml.res 1970-01-01 00:00:00 +0000
+++ test/rbkt/ExpQueryResults/zorba/debugger/dmh/break_response_no_info.xml.res 2011-12-13 11:51:46 +0000
@@ -0,0 +1,1 @@
+5 break
\ No newline at end of file
=== added directory 'test/rbkt/Queries/zorba/debugger'
=== added directory 'test/rbkt/Queries/zorba/debugger/dmh'
=== added file 'test/rbkt/Queries/zorba/debugger/dmh/break_response.xq'
--- test/rbkt/Queries/zorba/debugger/dmh/break_response.xq 1970-01-01 00:00:00 +0000
+++ test/rbkt/Queries/zorba/debugger/dmh/break_response.xq 2011-12-13 11:51:46 +0000
@@ -0,0 +1,5 @@
+import module namespace dmh = "http://www.zorba-xquery.com/modules/debugger/dbgp-message-handler";
+
+let $e := <response command="status" status="break" reason="ok" transaction_id="5">dmh:process#1 at file.xq:10</response>
+return
+ dmh:process($e)
=== added file 'test/rbkt/Queries/zorba/debugger/dmh/break_response_no_info.xq'
--- test/rbkt/Queries/zorba/debugger/dmh/break_response_no_info.xq 1970-01-01 00:00:00 +0000
+++ test/rbkt/Queries/zorba/debugger/dmh/break_response_no_info.xq 2011-12-13 11:51:46 +0000
@@ -0,0 +1,7 @@
+import module namespace dmh = "http://www.zorba-xquery.com/modules/debugger/dbgp-message-handler";
+
+let $e :=
+ <response command="status" status="break" reason="ok" transaction_id="5">
+ </response>
+return
+ dmh:process($e)