Implemented proper quoting of MI commands
authorJan Vrany <jan.vrany@fit.cvut.cz>
Tue, 11 Jul 2017 23:37:04 +0200
changeset 85 6fea1000a2a5
parent 84 7913863edaa6
child 86 7f53d51a0a65
Implemented proper quoting of MI commands ...as described in GDB MI documentation [1] by means of a (new) class `GDBMIPrinter`. `GDBCommand >> asString` has been changed to use `GDBMIPrinter`. [1]: https://sourceware.org/gdb/onlinedocs/gdb/GDB_002fMI-Input-Syntax.html#GDB_002fMI-Input-Syntax
GDBCLICommand.st
GDBCommand.st
GDBConnection.st
GDBDebugger.st
GDBMICommand.st
GDBMIParser.st
GDBMIPrinter.st
GDBMI_exec_run.st
GDBSelectedFrameChangedEvent.st
Make.proto
Make.spec
abbrev.stc
bc.mak
jv_libgdbs.st
libInit.cc
tests/GDBMIPrinterTests.st
tests/Make.proto
tests/Make.spec
tests/abbrev.stc
tests/bc.mak
tests/jv_libgdbs_tests.st
tests/libInit.cc
--- a/GDBCLICommand.st	Thu Jul 06 07:54:57 2017 +0200
+++ b/GDBCLICommand.st	Tue Jul 11 23:37:04 2017 +0200
@@ -28,19 +28,6 @@
     value := aString.
 ! !
 
-!GDBCLICommand methodsFor:'converting'!
-
-asString
-    "superclass GDBCommand says that I am responsible to implement this method"
-
-    ^ runOnBackground == true 
-        ifTrue:[self value", '&'" ]
-        ifFalse:[self value ].
-
-    "Created: / 02-06-2014 / 23:34:30 / Jan Vrany <jan.vrany@fit.cvut.cz>"
-    "Modified: / 27-02-2015 / 13:17:02 / Jan Vrany <jan.vrany@fit.cvut.cz>"
-! !
-
 !GDBCLICommand methodsFor:'testing'!
 
 isCLICommand
--- a/GDBCommand.st	Thu Jul 06 07:54:57 2017 +0200
+++ b/GDBCommand.st	Tue Jul 11 23:37:04 2017 +0200
@@ -31,9 +31,19 @@
 !GDBCommand methodsFor:'converting'!
 
 asString
-    ^ self subclassResponsibility
+    ^ String streamContents: [ :s | (GDBMIPrinter on: s) printCommand: self ]
+
+    "Created: / 09-06-2014 / 18:42:11 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+    "Modified: / 11-07-2017 / 23:14:14 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+! !
 
-    "Created: / 02-06-2014 / 23:34:21 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+!GDBCommand methodsFor:'printing & storing'!
+
+printOn: aStream
+    super printOn: aStream.
+    aStream nextPut: $(; nextPutAll: self asString; nextPut:$)
+
+    "Created: / 11-07-2017 / 23:23:19 / Jan Vrany <jan.vrany@fit.cvut.cz>"
 ! !
 
 !GDBCommand methodsFor:'testing'!
--- a/GDBConnection.st	Thu Jul 06 07:54:57 2017 +0200
+++ b/GDBConnection.st	Tue Jul 11 23:37:04 2017 +0200
@@ -67,9 +67,7 @@
 send: command
     | commandString |
 
-    commandString := command token notNil 
-                        ifTrue:[ command token printString , command asString ]
-                        ifFalse:[ commandString := command asString ].
+    commandString := command asString.
 
     outstandingCommands add: command.
     recorder notNil ifTrue:[ 
@@ -78,7 +76,7 @@
     process debuggerInput nextPutLine: commandString.
 
     "Created: / 20-06-2014 / 22:09:38 / Jan Vrany <jan.vrany@fit.cvut.cz>"
-    "Modified: / 23-06-2014 / 23:31:53 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+    "Modified: / 11-07-2017 / 22:39:48 / Jan Vrany <jan.vrany@fit.cvut.cz>"
 ! !
 
 !GDBConnection methodsFor:'event dispatching'!
--- a/GDBDebugger.st	Thu Jul 06 07:54:57 2017 +0200
+++ b/GDBDebugger.st	Tue Jul 11 23:37:04 2017 +0200
@@ -138,6 +138,9 @@
      command to finish and return the command result.  
      Otherwise, return nil immediately.
 
+     If `wait` is true and if command results in an error GDBError
+     is thrown.
+
      `command` may be either a GDBCommand or string, in which case it will
      be parsed into a GDBCommand.           
     "
@@ -169,7 +172,14 @@
         connection eventAnnouncer when:GDBCommandResultEvent do:handler1.
         connection pushEvent:(GDBCommandEvent new command:cmd).
         blocker wait.
+        result isError ifTrue:[
+            GDBError newException
+                parameter: result;
+                messageText: 'Command failed: ', (result propertyAt: 'msg');
+                raise.
+        ].
         result.
+
     ]
     ifFalse:[
         connection pushEvent:(GDBCommandEvent new command:cmd).
@@ -177,7 +187,7 @@
     ]
 
     "Created: / 02-06-2014 / 23:45:43 / Jan Vrany <jan.vrany@fit.cvut.cz>"
-    "Modified: / 08-03-2015 / 05:51:52 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+    "Modified: / 11-07-2017 / 21:14:32 / Jan Vrany <jan.vrany@fit.cvut.cz>"
 !
 
 send:command andWaitFor:eventHandlers
--- a/GDBMICommand.st	Thu Jul 06 07:54:57 2017 +0200
+++ b/GDBMICommand.st	Tue Jul 11 23:37:04 2017 +0200
@@ -227,26 +227,6 @@
     "Modified: / 12-06-2014 / 00:43:44 / Jan Vrany <jan.vrany@fit.cvut.cz>"
 ! !
 
-!GDBMICommand methodsFor:'converting'!
-
-asString
-    ^ String streamContents: [ :s |
-        | args |
-        s nextPut: $-.
-        s nextPutAll: self operation.
-        args := self arguments.
-        args notEmptyOrNil ifTrue:[ 
-            args do:[:each | 
-                s space.
-                s nextPutAll: each asString.
-            ].
-        ].
-    ]
-
-    "Created: / 09-06-2014 / 18:42:11 / Jan Vrany <jan.vrany@fit.cvut.cz>"
-    "Modified: / 20-06-2014 / 22:04:01 / Jan Vrany <jan.vrany@fit.cvut.cz>"
-! !
-
 !GDBMICommand methodsFor:'testing'!
 
 isMICommand
--- a/GDBMIParser.st	Thu Jul 06 07:54:57 2017 +0200
+++ b/GDBMIParser.st	Tue Jul 11 23:37:04 2017 +0200
@@ -11,6 +11,27 @@
 	category:'GDB-Private'
 !
 
+!GDBMIParser class methodsFor:'documentation'!
+
+documentation
+"
+    A parser that reads GDB MI output records from a stream
+    and converts them to objects.
+
+    See [1] for description of GDB MI output syntax.
+
+    [author:]
+        Jan Vrany <jan.vrany@fit.cvut.cz>
+
+    [instance variables:]
+
+    [class variables:]
+
+    [see also:]
+        [1]: https://sourceware.org/gdb/onlinedocs/gdb/GDB_002fMI-Output-Syntax.html#GDB_002fMI-Output-Syntax
+
+"
+! !
 
 !GDBMIParser class methodsFor:'instance creation'!
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/GDBMIPrinter.st	Tue Jul 11 23:37:04 2017 +0200
@@ -0,0 +1,237 @@
+"{ Encoding: utf8 }"
+
+"{ Package: 'jv:libgdbs' }"
+
+"{ NameSpace: Smalltalk }"
+
+Object subclass:#GDBMIPrinter
+	instanceVariableNames:'stream'
+	classVariableNames:''
+	poolDictionaries:''
+	category:'GDB-Private'
+!
+
+!GDBMIPrinter class methodsFor:'documentation'!
+
+documentation
+"
+    A writer that writes GDB commands to an MI channel usin
+    GDB MI input syntax [1].
+
+
+
+
+    [author:]
+        Jan Vrany <jan.vrany@fit.cvut.cz>
+
+    [instance variables:]
+
+    [class variables:]
+
+    [see also:]
+        [1]: https://sourceware.org/gdb/onlinedocs/gdb/GDB_002fMI-Input-Syntax.html#GDB_002fMI-Input-Syntax
+
+"
+! !
+
+!GDBMIPrinter class methodsFor:'instance creation'!
+
+on: aStream
+    ^ self new setStream: aStream.
+
+    "Created: / 11-07-2017 / 21:21:58 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+! !
+
+!GDBMIPrinter methodsFor:'initialization'!
+
+setStream: aStream
+    stream := aStream
+
+    "Created: / 11-07-2017 / 21:22:15 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+! !
+
+!GDBMIPrinter methodsFor:'printing'!
+
+printCEscapedCharacter: aCharacter
+    stream nextPut: $\.
+    aCharacter == $" ifTrue:[ stream nextPut: $". ^ self ].
+    aCharacter == $\ ifTrue:[ stream nextPut: $\. ^ self ].
+    aCharacter == Character backspace ifTrue:[ stream nextPut: $b. ^ self ].
+    aCharacter == Character tab ifTrue:[ stream nextPut: $t. ^ self ].
+    aCharacter == Character linefeed ifTrue:[ stream nextPut: $n. ^ self ].
+    aCharacter == Character return ifTrue:[ stream nextPut: $r. ^ self ].   
+    aCharacter == Character newPage ifTrue:[ stream nextPut: $f. ^ self ]. 
+    aCharacter codePoint <= 16rFF ifTrue:[ 
+        stream nextPut: $x.
+        aCharacter codePoint printOn: stream base: 16.
+        ^ self.
+    ].
+    GDBError raiseErrorString: 'Unrepresentable character: \U', (aCharacter codePoint printStringRadix: 16)
+
+    "Created: / 11-07-2017 / 22:12:10 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+!
+
+printCString: aString
+    "
+    c-string → ''' seven-bit-iso-c-string-content '''
+    "
+    | start stop |
+    stream nextPut: $".
+    start := 1.
+    [ start <= aString size ] whileTrue:[ 
+        | char |
+        stop := start.
+        [ 
+          stop > aString size ifTrue:[ 
+            stream nextPutAll:aString startingAt: start to: stop - 1.
+            stream nextPut: $".   
+            ^ self.
+          ].
+          char := aString at: stop. 
+          stop := stop + 1.
+          char == Character space or:[(self needCEscaping: char) not] ] whileTrue.
+        stream nextPutAll:aString startingAt: start to: stop - 2.
+        self printCEscapedCharacter: char.
+        start := stop.
+    ].
+    stream nextPut: $".
+
+    "Created: / 11-07-2017 / 22:05:15 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+!
+
+printCommand: aGDBCommand
+    "
+    command → cli-command | mi-command
+    "
+    aGDBCommand isMICommand ifTrue:[ 
+        self printCommandMI: aGDBCommand
+    ] ifFalse:[ 
+        self printCommandCLI: aGDBCommand.
+    ].
+
+    "Created: / 11-07-2017 / 21:29:15 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+!
+
+printCommandCLI: aGDBCLICommand
+    "
+    cli-command → [ token ] cli-command nl, where cli-command is any existing GDB CLI command.
+
+    "
+    aGDBCLICommand token notNil ifTrue:[ 
+        aGDBCLICommand token printOn: stream.
+    ].
+    stream nextPutAll: aGDBCLICommand value.
+
+    "Created: / 11-07-2017 / 21:33:00 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+!
+
+printCommandMI: aGDBMICommand
+    "
+    mi-command → [ token ] '-' operation ( ' ' option )* [ ' --' ] ( ' ' parameter )* nl
+    "
+
+    | maybeOption |
+
+    aGDBMICommand token notNil ifTrue:[ 
+        aGDBMICommand token printOn: stream.
+    ].
+    stream nextPut:$-; nextPutAll: aGDBMICommand operation.
+
+    "/ Now, this is tricky. We have no distinction between options :-(
+    maybeOption := true.
+    aGDBMICommand arguments notEmptyOrNil ifTrue:[
+        aGDBMICommand arguments do:[:each | 
+            | eachAsString |
+
+            eachAsString := each asString.
+            stream space.
+            eachAsString = '--' ifTrue:[ 
+                maybeOption := false.
+                stream nextPutAll: '--'.
+            ].
+            (maybeOption and:[eachAsString first = $-]) ifTrue:[
+                self printOption: eachAsString
+            ] ifFalse:[ 
+                self printParameter: eachAsString.
+            ].
+        ].
+    ].
+
+    "Created: / 11-07-2017 / 21:36:31 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+    "Modified: / 11-07-2017 / 22:56:35 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+!
+
+printNl
+    "
+    nl → CR | CR-LF 
+
+    "
+    stream nextPut: Character return.
+
+    "Created: / 11-07-2017 / 21:33:35 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+!
+
+printNonBlankSequence: aString
+    "
+    non-blank-sequence → anything, provided it doesn’t contain special characters such as '-', nl, ''' and of course ' '
+    "    
+    stream nextPutAll: aString
+
+    "Created: / 11-07-2017 / 21:54:29 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+!
+
+printOption: aString
+    "
+    option → '-' parameter [ ' ' parameter ]
+    "
+    | i |
+
+    i := 1.
+    [ i <= aString size and:[ (aString at: i) == $- ] ] whileTrue:[
+        i := i + 1.
+    ].
+    i to: aString size do:[:i |
+        | c |
+
+        c := aString at: i.
+        (self needCEscaping: c) ifTrue:[ 
+            self printParameter: aString.
+            ^ self
+        ].
+    ].
+    stream nextPutAll: aString.
+
+    "Created: / 11-07-2017 / 21:51:11 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+    "Modified: / 11-07-2017 / 23:21:57 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+!
+
+printParameter: aString
+    "
+    parameter → non-blank-sequence | c-string
+    "    
+    (self isNonBlankSequence: aString) ifTrue:[
+        self printNonBlankSequence: aString
+    ] ifFalse:[ 
+        self printCString: aString
+    ].
+
+    "Created: / 11-07-2017 / 21:52:35 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+! !
+
+!GDBMIPrinter methodsFor:'testing'!
+
+isNonBlankSequence: aString
+    ^ aString allSatisfy:[:each | (self needCEscaping: each) not ].
+
+    "Created: / 11-07-2017 / 21:53:31 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+    "Modified: / 11-07-2017 / 23:26:51 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+!
+
+needCEscaping: aCharacter
+    ^ aCharacter == $\ 
+        or:[ aCharacter == $" 
+        or:[ (aCharacter codePoint between: 33 and: 16r7F) not ]]
+
+    "Created: / 11-07-2017 / 22:42:19 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+! !
+
--- a/GDBMI_exec_run.st	Thu Jul 06 07:54:57 2017 +0200
+++ b/GDBMI_exec_run.st	Tue Jul 11 23:37:04 2017 +0200
@@ -104,9 +104,10 @@
     "/ See https://sourceware.org/bugzilla/show_bug.cgi?id=18077
     "/ 
     "/ As a (temporary) workaround, substitute for CLI command here.
-    ^ 'r &'
+    ^ (token notNil ifTrue:[token printString ] ifFalse:['']) , 'r &'
 
     "Created: / 04-03-2015 / 20:49:20 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+    "Modified: / 11-07-2017 / 23:31:08 / Jan Vrany <jan.vrany@fit.cvut.cz>"
 ! !
 
 !GDBMI_exec_run class methodsFor:'documentation'!
--- a/GDBSelectedFrameChangedEvent.st	Thu Jul 06 07:54:57 2017 +0200
+++ b/GDBSelectedFrameChangedEvent.st	Tue Jul 11 23:37:04 2017 +0200
@@ -9,6 +9,7 @@
 	category:'GDB-Core-Events'
 !
 
+
 !GDBSelectedFrameChangedEvent methodsFor:'initialization'!
 
 setFrame: aGDBFrame
@@ -18,3 +19,10 @@
     "Created: / 07-09-2014 / 23:12:58 / Jan Vrany <jan.vrany@fit.cvut.cz>"
 ! !
 
+!GDBSelectedFrameChangedEvent class methodsFor:'documentation'!
+
+version_HG
+
+    ^ '$Changeset: <not expanded> $'
+! !
+
--- a/Make.proto	Thu Jul 06 07:54:57 2017 +0200
+++ b/Make.proto	Tue Jul 11 23:37:04 2017 +0200
@@ -34,7 +34,7 @@
 # add the path(es) here:,
 # ********** OPTIONAL: MODIFY the next lines ***
 # LOCALINCLUDES=-Ifoo -Ibar
-LOCALINCLUDES= -I$(INCLUDE_TOP)/stx/goodies/announcements -I$(INCLUDE_TOP)/stx/goodies/magritte -I$(INCLUDE_TOP)/stx/goodies/sunit -I$(INCLUDE_TOP)/stx/libbasic -I$(INCLUDE_TOP)/stx/libbasic2 -I$(INCLUDE_TOP)/stx/libview2
+LOCALINCLUDES= -I$(INCLUDE_TOP)/stx/goodies/announcements -I$(INCLUDE_TOP)/stx/goodies/magritte -I$(INCLUDE_TOP)/stx/libbasic -I$(INCLUDE_TOP)/stx/libbasic2 -I$(INCLUDE_TOP)/stx/libtool -I$(INCLUDE_TOP)/stx/libview2 -I$(INCLUDE_TOP)/stx/libwidg
 
 
 # if you need any additional defines for embedded C code,
@@ -137,6 +137,7 @@
 $(OUTDIR)GDBInternalPipeStream.$(O) GDBInternalPipeStream.$(C) GDBInternalPipeStream.$(H): GDBInternalPipeStream.st $(INCLUDE_TOP)/stx/libbasic/Object.$(H) $(INCLUDE_TOP)/stx/libbasic/Stream.$(H) $(STCHDR)
 $(OUTDIR)GDBMAContainer.$(O) GDBMAContainer.$(C) GDBMAContainer.$(H): GDBMAContainer.st $(INCLUDE_TOP)/stx/goodies/magritte/Magritte__MAContainer.$(H) $(INCLUDE_TOP)/stx/goodies/magritte/Magritte__MADescription.$(H) $(INCLUDE_TOP)/stx/goodies/magritte/Magritte__MAObject.$(H) $(INCLUDE_TOP)/stx/libbasic/Object.$(H) $(STCHDR)
 $(OUTDIR)GDBMAPropertyAccessor.$(O) GDBMAPropertyAccessor.$(C) GDBMAPropertyAccessor.$(H): GDBMAPropertyAccessor.st $(INCLUDE_TOP)/stx/goodies/magritte/Magritte__MAAccessor.$(H) $(INCLUDE_TOP)/stx/goodies/magritte/Magritte__MAObject.$(H) $(INCLUDE_TOP)/stx/libbasic/Object.$(H) $(STCHDR)
+$(OUTDIR)GDBMIPrinter.$(O) GDBMIPrinter.$(C) GDBMIPrinter.$(H): GDBMIPrinter.st $(INCLUDE_TOP)/stx/libbasic/Object.$(H) $(STCHDR)
 $(OUTDIR)GDBObject.$(O) GDBObject.$(C) GDBObject.$(H): GDBObject.st $(INCLUDE_TOP)/stx/libbasic/Object.$(H) $(STCHDR)
 $(OUTDIR)GDBPTY.$(O) GDBPTY.$(C) GDBPTY.$(H): GDBPTY.st $(INCLUDE_TOP)/stx/libbasic/Object.$(H) $(INCLUDE_TOP)/stx/libbasic/TTYConstants.$(H) $(STCHDR)
 $(OUTDIR)GDBProcess.$(O) GDBProcess.$(C) GDBProcess.$(H): GDBProcess.st $(INCLUDE_TOP)/stx/libbasic/Object.$(H) $(STCHDR)
--- a/Make.spec	Thu Jul 06 07:54:57 2017 +0200
+++ b/Make.spec	Tue Jul 11 23:37:04 2017 +0200
@@ -61,6 +61,7 @@
 	GDBInternalPipeStream \
 	GDBMAContainer \
 	GDBMAPropertyAccessor \
+	GDBMIPrinter \
 	GDBObject \
 	GDBPTY \
 	GDBProcess \
@@ -249,6 +250,7 @@
     $(OUTDIR)GDBInternalPipeStream.$(O) \
     $(OUTDIR)GDBMAContainer.$(O) \
     $(OUTDIR)GDBMAPropertyAccessor.$(O) \
+    $(OUTDIR)GDBMIPrinter.$(O) \
     $(OUTDIR)GDBObject.$(O) \
     $(OUTDIR)GDBPTY.$(O) \
     $(OUTDIR)GDBProcess.$(O) \
--- a/abbrev.stc	Thu Jul 06 07:54:57 2017 +0200
+++ b/abbrev.stc	Tue Jul 11 23:37:04 2017 +0200
@@ -11,6 +11,7 @@
 GDBInternalPipeStream GDBInternalPipeStream jv:libgdbs 'GDB-Support' 0
 GDBMAContainer GDBMAContainer jv:libgdbs 'GDB-Support' 0
 GDBMAPropertyAccessor GDBMAPropertyAccessor jv:libgdbs 'GDB-Support' 0
+GDBMIPrinter GDBMIPrinter jv:libgdbs 'GDB-Private' 0
 GDBObject GDBObject jv:libgdbs 'GDB-Core' 0
 GDBPTY GDBPTY jv:libgdbs 'GDB-Private' 0
 GDBProcess GDBProcess jv:libgdbs 'GDB-Private' 0
--- a/bc.mak	Thu Jul 06 07:54:57 2017 +0200
+++ b/bc.mak	Tue Jul 11 23:37:04 2017 +0200
@@ -35,7 +35,7 @@
 
 
 
-LOCALINCLUDES= -I$(INCLUDE_TOP)\stx\goodies\announcements -I$(INCLUDE_TOP)\stx\goodies\magritte -I$(INCLUDE_TOP)\stx\goodies\sunit -I$(INCLUDE_TOP)\stx\libbasic -I$(INCLUDE_TOP)\stx\libbasic2 -I$(INCLUDE_TOP)\stx\libview2
+LOCALINCLUDES= -I$(INCLUDE_TOP)\stx\goodies\announcements -I$(INCLUDE_TOP)\stx\goodies\magritte -I$(INCLUDE_TOP)\stx\libbasic -I$(INCLUDE_TOP)\stx\libbasic2 -I$(INCLUDE_TOP)\stx\libtool -I$(INCLUDE_TOP)\stx\libview2 -I$(INCLUDE_TOP)\stx\libwidg
 LOCALDEFINES=
 
 STCLOCALOPT=-package=$(PACKAGE) -I. $(LOCALINCLUDES) -headerDir=. $(STCLOCALOPTIMIZATIONS) $(STCWARNINGS) $(LOCALDEFINES)  -varPrefix=$(LIBNAME)
@@ -84,6 +84,7 @@
 $(OUTDIR)GDBInternalPipeStream.$(O) GDBInternalPipeStream.$(C) GDBInternalPipeStream.$(H): GDBInternalPipeStream.st $(INCLUDE_TOP)\stx\libbasic\Object.$(H) $(INCLUDE_TOP)\stx\libbasic\Stream.$(H) $(STCHDR)
 $(OUTDIR)GDBMAContainer.$(O) GDBMAContainer.$(C) GDBMAContainer.$(H): GDBMAContainer.st $(INCLUDE_TOP)\stx\goodies\magritte\Magritte__MAContainer.$(H) $(INCLUDE_TOP)\stx\goodies\magritte\Magritte__MADescription.$(H) $(INCLUDE_TOP)\stx\goodies\magritte\Magritte__MAObject.$(H) $(INCLUDE_TOP)\stx\libbasic\Object.$(H) $(STCHDR)
 $(OUTDIR)GDBMAPropertyAccessor.$(O) GDBMAPropertyAccessor.$(C) GDBMAPropertyAccessor.$(H): GDBMAPropertyAccessor.st $(INCLUDE_TOP)\stx\goodies\magritte\Magritte__MAAccessor.$(H) $(INCLUDE_TOP)\stx\goodies\magritte\Magritte__MAObject.$(H) $(INCLUDE_TOP)\stx\libbasic\Object.$(H) $(STCHDR)
+$(OUTDIR)GDBMIPrinter.$(O) GDBMIPrinter.$(C) GDBMIPrinter.$(H): GDBMIPrinter.st $(INCLUDE_TOP)\stx\libbasic\Object.$(H) $(STCHDR)
 $(OUTDIR)GDBObject.$(O) GDBObject.$(C) GDBObject.$(H): GDBObject.st $(INCLUDE_TOP)\stx\libbasic\Object.$(H) $(STCHDR)
 $(OUTDIR)GDBPTY.$(O) GDBPTY.$(C) GDBPTY.$(H): GDBPTY.st $(INCLUDE_TOP)\stx\libbasic\Object.$(H) $(INCLUDE_TOP)\stx\libbasic\TTYConstants.$(H) $(STCHDR)
 $(OUTDIR)GDBProcess.$(O) GDBProcess.$(C) GDBProcess.$(H): GDBProcess.st $(INCLUDE_TOP)\stx\libbasic\Object.$(H) $(STCHDR)
--- a/jv_libgdbs.st	Thu Jul 06 07:54:57 2017 +0200
+++ b/jv_libgdbs.st	Tue Jul 11 23:37:04 2017 +0200
@@ -49,9 +49,10 @@
      Please also take a look at the #mandatoryPreRequisites method"
 
     ^ #(
-        #'stx:goodies/sunit'    "TestAsserter - superclass of GDBSimulatorResource"
-        #'stx:libbasic2'    "List - referenced by GDBDebugger>>onThreadGroupAddedEvent:"
+        #'stx:libbasic2'    "List - referenced by GDBDebugger>>breakpoints"
+        #'stx:libtool'    "Tools::Inspector2Tab - referenced by GDBBreakpoint>>inspector2TabCondition"
         #'stx:libview2'    "ApplicationModel - referenced by GDBEventSubscription class>>blockFor:withSelector:"
+        #'stx:libwidg'    "EditTextView - referenced by GDBBreakpoint>>inspector2TabCondition"
     )
 !
 
@@ -85,6 +86,7 @@
         GDBInternalPipeStream
         GDBMAContainer
         GDBMAPropertyAccessor
+        GDBMIPrinter
         GDBObject
         GDBPTY
         GDBProcess
--- a/libInit.cc	Thu Jul 06 07:54:57 2017 +0200
+++ b/libInit.cc	Tue Jul 11 23:37:04 2017 +0200
@@ -26,6 +26,7 @@
 extern void _GDBInternalPipeStream_Init(int pass, struct __vmData__ *__pRT__, OBJ snd);
 extern void _GDBMAContainer_Init(int pass, struct __vmData__ *__pRT__, OBJ snd);
 extern void _GDBMAPropertyAccessor_Init(int pass, struct __vmData__ *__pRT__, OBJ snd);
+extern void _GDBMIPrinter_Init(int pass, struct __vmData__ *__pRT__, OBJ snd);
 extern void _GDBObject_Init(int pass, struct __vmData__ *__pRT__, OBJ snd);
 extern void _GDBPTY_Init(int pass, struct __vmData__ *__pRT__, OBJ snd);
 extern void _GDBProcess_Init(int pass, struct __vmData__ *__pRT__, OBJ snd);
@@ -223,6 +224,7 @@
     _GDBInternalPipeStream_Init(pass,__pRT__,snd);
     _GDBMAContainer_Init(pass,__pRT__,snd);
     _GDBMAPropertyAccessor_Init(pass,__pRT__,snd);
+    _GDBMIPrinter_Init(pass,__pRT__,snd);
     _GDBObject_Init(pass,__pRT__,snd);
     _GDBPTY_Init(pass,__pRT__,snd);
     _GDBProcess_Init(pass,__pRT__,snd);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/GDBMIPrinterTests.st	Tue Jul 11 23:37:04 2017 +0200
@@ -0,0 +1,85 @@
+"{ Package: 'jv:libgdbs/tests' }"
+
+"{ NameSpace: Smalltalk }"
+
+TestCase subclass:#GDBMIPrinterTests
+	instanceVariableNames:'stream printer'
+	classVariableNames:''
+	poolDictionaries:''
+	category:'GDB-Private-Tests'
+!
+
+
+!GDBMIPrinterTests methodsFor:'running'!
+
+setUp
+    stream := String new writeStream.
+    printer := GDBMIPrinter on: stream.
+
+    "Created: / 11-07-2017 / 22:15:28 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+! !
+
+!GDBMIPrinterTests methodsFor:'tests'!
+
+testCString
+
+    printer printCString:'aaa'.
+    self assert: stream contents equals: '"aaa"'.
+    stream reset.
+
+    printer printCString:'abc', Character tab, 'xyz'.
+    self assert: stream contents equals: '"abc\txyz"'.
+    stream reset.
+
+    printer printCString:'abc\\xyz'.
+    self assert: stream contents equals: '"abc\\\\xyz"'.
+    stream reset.
+
+    printer printCString:'a "bcxy" z'.
+    self assert: stream contents equals: '"a \"bcxy\" z"'.
+    stream reset.
+
+    printer printCString:'a z'.
+    self assert: stream contents equals: '"a z"'.
+    stream reset.
+
+    printer printCString:'a', (Character codePoint: 16r80).
+    self assert: stream contents equals: '"a\x80"'.
+    stream reset.
+
+    "Created: / 11-07-2017 / 22:13:43 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+    "Modified: / 11-07-2017 / 23:55:46 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+!
+
+testOption
+
+    printer printOption:'aaa'.
+    self assert: stream contents equals: 'aaa'.
+    stream reset.
+
+    printer printOption:'-t'.
+    self assert: stream contents equals: '-t'.
+    stream reset.
+
+    printer printOption:'--thread'.
+    self assert: stream contents equals: '--thread'.
+    stream reset.
+
+    printer printOption:'a "bcxy" z'.
+    self assert: stream contents equals: '"a \"bcxy\" z"'.
+    stream reset.
+
+    printer printOption:'100'.
+    self assert: stream contents equals: '100'.
+    stream reset.
+
+    "Created: / 11-07-2017 / 23:21:03 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+! !
+
+!GDBMIPrinterTests class methodsFor:'documentation'!
+
+version_HG
+
+    ^ '$Changeset: <not expanded> $'
+! !
+
--- a/tests/Make.proto	Thu Jul 06 07:54:57 2017 +0200
+++ b/tests/Make.proto	Tue Jul 11 23:37:04 2017 +0200
@@ -133,6 +133,7 @@
 $(OUTDIR)GDBDebuggerTestCase.$(O) GDBDebuggerTestCase.$(C) GDBDebuggerTestCase.$(H): GDBDebuggerTestCase.st $(INCLUDE_TOP)/stx/goodies/sunit/TestAsserter.$(H) $(INCLUDE_TOP)/stx/goodies/sunit/TestCase.$(H) $(INCLUDE_TOP)/stx/libbasic/Object.$(H) $(STCHDR)
 $(OUTDIR)GDBInternalPipeStreamTests.$(O) GDBInternalPipeStreamTests.$(C) GDBInternalPipeStreamTests.$(H): GDBInternalPipeStreamTests.st $(INCLUDE_TOP)/stx/goodies/sunit/TestAsserter.$(H) $(INCLUDE_TOP)/stx/goodies/sunit/TestCase.$(H) $(INCLUDE_TOP)/stx/libbasic/Object.$(H) $(STCHDR)
 $(OUTDIR)GDBMIParserTests.$(O) GDBMIParserTests.$(C) GDBMIParserTests.$(H): GDBMIParserTests.st $(INCLUDE_TOP)/jv/libgdbs/GDBCommandStatus.$(H) $(INCLUDE_TOP)/stx/goodies/sunit/TestAsserter.$(H) $(INCLUDE_TOP)/stx/goodies/sunit/TestCase.$(H) $(INCLUDE_TOP)/stx/libbasic/Object.$(H) $(STCHDR)
+$(OUTDIR)GDBMIPrinterTests.$(O) GDBMIPrinterTests.$(C) GDBMIPrinterTests.$(H): GDBMIPrinterTests.st $(INCLUDE_TOP)/stx/goodies/sunit/TestAsserter.$(H) $(INCLUDE_TOP)/stx/goodies/sunit/TestCase.$(H) $(INCLUDE_TOP)/stx/libbasic/Object.$(H) $(STCHDR)
 $(OUTDIR)GDBSimulatorProcessTests.$(O) GDBSimulatorProcessTests.$(C) GDBSimulatorProcessTests.$(H): GDBSimulatorProcessTests.st $(INCLUDE_TOP)/jv/libgdbs/GDBCommandStatus.$(H) $(INCLUDE_TOP)/stx/goodies/sunit/TestAsserter.$(H) $(INCLUDE_TOP)/stx/goodies/sunit/TestCase.$(H) $(INCLUDE_TOP)/stx/libbasic/Object.$(H) $(STCHDR)
 $(OUTDIR)jv_libgdbs_tests.$(O) jv_libgdbs_tests.$(C) jv_libgdbs_tests.$(H): jv_libgdbs_tests.st $(INCLUDE_TOP)/stx/libbasic/LibraryDefinition.$(H) $(INCLUDE_TOP)/stx/libbasic/Object.$(H) $(INCLUDE_TOP)/stx/libbasic/ProjectDefinition.$(H) $(STCHDR)
 $(OUTDIR)GDBDebuggerTestsR.$(O) GDBDebuggerTestsR.$(C) GDBDebuggerTestsR.$(H): GDBDebuggerTestsR.st $(INCLUDE_TOP)/jv/libgdbs/tests/GDBDebuggerTestCase.$(H) $(INCLUDE_TOP)/stx/goodies/sunit/TestAsserter.$(H) $(INCLUDE_TOP)/stx/goodies/sunit/TestCase.$(H) $(INCLUDE_TOP)/stx/libbasic/Object.$(H) $(STCHDR)
--- a/tests/Make.spec	Thu Jul 06 07:54:57 2017 +0200
+++ b/tests/Make.spec	Tue Jul 11 23:37:04 2017 +0200
@@ -55,6 +55,7 @@
 	GDBDebuggerTestCase \
 	GDBInternalPipeStreamTests \
 	GDBMIParserTests \
+	GDBMIPrinterTests \
 	GDBSimulatorProcessTests \
 	jv_libgdbs_tests \
 	GDBDebuggerTestsR \
@@ -68,6 +69,7 @@
     $(OUTDIR)GDBDebuggerTestCase.$(O) \
     $(OUTDIR)GDBInternalPipeStreamTests.$(O) \
     $(OUTDIR)GDBMIParserTests.$(O) \
+    $(OUTDIR)GDBMIPrinterTests.$(O) \
     $(OUTDIR)GDBSimulatorProcessTests.$(O) \
     $(OUTDIR)jv_libgdbs_tests.$(O) \
     $(OUTDIR)GDBDebuggerTestsR.$(O) \
--- a/tests/abbrev.stc	Thu Jul 06 07:54:57 2017 +0200
+++ b/tests/abbrev.stc	Tue Jul 11 23:37:04 2017 +0200
@@ -5,6 +5,7 @@
 GDBDebuggerTestCase GDBDebuggerTestCase jv:libgdbs/tests 'GDB-Core-Tests' 1
 GDBInternalPipeStreamTests GDBInternalPipeStreamTests jv:libgdbs/tests 'GDB-Support-Tests' 1
 GDBMIParserTests GDBMIParserTests jv:libgdbs/tests 'GDB-Private-Tests' 1
+GDBMIPrinterTests GDBMIPrinterTests jv:libgdbs/tests 'GDB-Private-Tests' 1
 GDBSimulatorProcessTests GDBSimulatorProcessTests jv:libgdbs/tests 'GDB-Private-Tests' 1
 jv_libgdbs_tests jv_libgdbs_tests jv:libgdbs/tests '* Projects & Packages *' 3
 GDBDebuggerTestsR GDBDebuggerTestsR jv:libgdbs/tests 'GDB-Core-Tests' 1
--- a/tests/bc.mak	Thu Jul 06 07:54:57 2017 +0200
+++ b/tests/bc.mak	Tue Jul 11 23:37:04 2017 +0200
@@ -80,6 +80,7 @@
 $(OUTDIR)GDBDebuggerTestCase.$(O) GDBDebuggerTestCase.$(C) GDBDebuggerTestCase.$(H): GDBDebuggerTestCase.st $(INCLUDE_TOP)\stx\goodies\sunit\TestAsserter.$(H) $(INCLUDE_TOP)\stx\goodies\sunit\TestCase.$(H) $(INCLUDE_TOP)\stx\libbasic\Object.$(H) $(STCHDR)
 $(OUTDIR)GDBInternalPipeStreamTests.$(O) GDBInternalPipeStreamTests.$(C) GDBInternalPipeStreamTests.$(H): GDBInternalPipeStreamTests.st $(INCLUDE_TOP)\stx\goodies\sunit\TestAsserter.$(H) $(INCLUDE_TOP)\stx\goodies\sunit\TestCase.$(H) $(INCLUDE_TOP)\stx\libbasic\Object.$(H) $(STCHDR)
 $(OUTDIR)GDBMIParserTests.$(O) GDBMIParserTests.$(C) GDBMIParserTests.$(H): GDBMIParserTests.st $(INCLUDE_TOP)\jv\libgdbs\GDBCommandStatus.$(H) $(INCLUDE_TOP)\stx\goodies\sunit\TestAsserter.$(H) $(INCLUDE_TOP)\stx\goodies\sunit\TestCase.$(H) $(INCLUDE_TOP)\stx\libbasic\Object.$(H) $(STCHDR)
+$(OUTDIR)GDBMIPrinterTests.$(O) GDBMIPrinterTests.$(C) GDBMIPrinterTests.$(H): GDBMIPrinterTests.st $(INCLUDE_TOP)\stx\goodies\sunit\TestAsserter.$(H) $(INCLUDE_TOP)\stx\goodies\sunit\TestCase.$(H) $(INCLUDE_TOP)\stx\libbasic\Object.$(H) $(STCHDR)
 $(OUTDIR)GDBSimulatorProcessTests.$(O) GDBSimulatorProcessTests.$(C) GDBSimulatorProcessTests.$(H): GDBSimulatorProcessTests.st $(INCLUDE_TOP)\jv\libgdbs\GDBCommandStatus.$(H) $(INCLUDE_TOP)\stx\goodies\sunit\TestAsserter.$(H) $(INCLUDE_TOP)\stx\goodies\sunit\TestCase.$(H) $(INCLUDE_TOP)\stx\libbasic\Object.$(H) $(STCHDR)
 $(OUTDIR)jv_libgdbs_tests.$(O) jv_libgdbs_tests.$(C) jv_libgdbs_tests.$(H): jv_libgdbs_tests.st $(INCLUDE_TOP)\stx\libbasic\LibraryDefinition.$(H) $(INCLUDE_TOP)\stx\libbasic\Object.$(H) $(INCLUDE_TOP)\stx\libbasic\ProjectDefinition.$(H) $(STCHDR)
 $(OUTDIR)GDBDebuggerTestsR.$(O) GDBDebuggerTestsR.$(C) GDBDebuggerTestsR.$(H): GDBDebuggerTestsR.st $(INCLUDE_TOP)\jv\libgdbs\tests\GDBDebuggerTestCase.$(H) $(INCLUDE_TOP)\stx\goodies\sunit\TestAsserter.$(H) $(INCLUDE_TOP)\stx\goodies\sunit\TestCase.$(H) $(INCLUDE_TOP)\stx\libbasic\Object.$(H) $(STCHDR)
--- a/tests/jv_libgdbs_tests.st	Thu Jul 06 07:54:57 2017 +0200
+++ b/tests/jv_libgdbs_tests.st	Tue Jul 11 23:37:04 2017 +0200
@@ -77,6 +77,7 @@
         GDBDebuggerTestCase
         GDBInternalPipeStreamTests
         GDBMIParserTests
+        GDBMIPrinterTests
         GDBSimulatorProcessTests
         #'jv_libgdbs_tests'
         GDBDebuggerTestsR
--- a/tests/libInit.cc	Thu Jul 06 07:54:57 2017 +0200
+++ b/tests/libInit.cc	Tue Jul 11 23:37:04 2017 +0200
@@ -20,6 +20,7 @@
 extern void _GDBDebuggerTestCase_Init(int pass, struct __vmData__ *__pRT__, OBJ snd);
 extern void _GDBInternalPipeStreamTests_Init(int pass, struct __vmData__ *__pRT__, OBJ snd);
 extern void _GDBMIParserTests_Init(int pass, struct __vmData__ *__pRT__, OBJ snd);
+extern void _GDBMIPrinterTests_Init(int pass, struct __vmData__ *__pRT__, OBJ snd);
 extern void _GDBSimulatorProcessTests_Init(int pass, struct __vmData__ *__pRT__, OBJ snd);
 extern void _jv_137libgdbs_137tests_Init(int pass, struct __vmData__ *__pRT__, OBJ snd);
 extern void _GDBDebuggerTestsR_Init(int pass, struct __vmData__ *__pRT__, OBJ snd);
@@ -42,6 +43,7 @@
     _GDBDebuggerTestCase_Init(pass,__pRT__,snd);
     _GDBInternalPipeStreamTests_Init(pass,__pRT__,snd);
     _GDBMIParserTests_Init(pass,__pRT__,snd);
+    _GDBMIPrinterTests_Init(pass,__pRT__,snd);
     _GDBSimulatorProcessTests_Init(pass,__pRT__,snd);
     _jv_137libgdbs_137tests_Init(pass,__pRT__,snd);
     _GDBDebuggerTestsR_Init(pass,__pRT__,snd);