GDBMIPrinter.st
author Jan Vrany <jan.vrany@fit.cvut.cz>
Sat, 19 Jan 2019 23:25:55 +0000
changeset 169 a3d1f59e3bfd
parent 153 dd55019f1d86
child 174 18ef81a3fee5
permissions -rw-r--r--
API: add `GDBDebugger >> getParameter:` and `setParameter:to:` ...to get / set GDB internal parameters such as prompt. The only complication here is that when a parameter is set by MI `-gdb-set` command, the `=cmd-param-changed' notification is not sent. This may or may not be a GDB bug. To make this transparent to `libgdbs` clients, intercept all `-gdb-set` commands and when sucessful, emit the event manually. This way, client may rely on value change notification (`GDBCmdParamChangedEvent`) to detect changes.

"{ Encoding: utf8 }"

"
jv:libgdbs - GNU Debugger Interface Library
Copyright (C) 2015-now Jan Vrany

This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License. 

This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
"
"{ Package: 'jv:libgdbs' }"

"{ NameSpace: Smalltalk }"

Object subclass:#GDBMIPrinter
	instanceVariableNames:'stream'
	classVariableNames:''
	poolDictionaries:''
	category:'GDB-Private'
!

!GDBMIPrinter class methodsFor:'documentation'!

copyright
"
jv:libgdbs - GNU Debugger Interface Library
Copyright (C) 2015-now Jan Vrany

This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License. 

This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
"
!

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 signal: 'Unrepresentable character: \U', (aCharacter codePoint printStringRadix: 16)

    "Created: / 11-07-2017 / 22:12:10 / Jan Vrany <jan.vrany@fit.cvut.cz>"
    "Modified: / 21-10-2018 / 08:06:56 / 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: '--'.
            ] ifFalse:[
                (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: / 22-06-2018 / 12:00:43 / 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>"
! !