# This file defines handy gdb macros for printing out Qt types
# To use it, add this line to your ~/.gdbinit :
# source /path/to/kde/sources/kdesdk/scripts/kde-devel-gdb

# Please don't use tabs in this file. When pasting a
# macro definition to gdb, tabs are interpreted as completion.

# Note for macro development: when working a macro,
# disable the confirmation before gdb allows to redefine a macro, using "set confirm 0".

# Disable printing of static members. Qt has too many, it clutters the output
set print static-members off

# Remember history over restarts
set history save
set history filename ~/.gdb_history

# Show the real classname of object instances - e.g. (Kded *) 0x8073440 instead of (class QObject *) 0x8073440
set print object

define printq4string
    printq4stringdata ($arg0).d
end
document printq4string
  Prints the contents of a Qt4 QString
end
define printq5string
    printq5stringdata ($arg0).d
end
document printq5string
  Prints the contents of a Qt5 QString
end

define printq4stringdata
    set $d = ('QString::Data'*) $arg0
    set $i = 0
    # abort after a '-1' character, to avoid going on forever when printing a garbage string
    while $i < $d->size && ($i == 0 || (char)$d->data[$i-1] != -1)
        printf "%c", (char)($d->data[$i++] & 0xff)
    end
    printf "\n"
end
document printq4stringdata
  Prints the contents of a Qt4 QString::Data
  This is useful when the output of another command (e.g. printqmap)
  shows {d = 0xdeadbeef} for a QString, i.e. the qstringdata address
  instead of the QString object itself.
  printq4string $s and printq4stringdata $s.d are equivalent.
end

define printq5stringdata
    set $d = ('QString::Data'*) $arg0
    set $data_char = (char*)$d + $d->offset
    set $data = (unsigned short*) $data_char
    set $size = $d->size
    set $i = 0
    while $i < $size
      set $c = (char)($data[$i++] & 0xff)
      printf "%c", $c
      # abort after a '-1' character, to avoid going on forever when printing a garbage string
      if $i != 0 && $c == -1
        printf "\n<output terminated: junk data?>"
        loop_break
      end
    end
    printf "\n"
end
document printq5stringdata
  Prints the contents of a Qt5 QString::Data
  This is useful when the output of another command (e.g. printqmap)
  shows {d = 0xdeadbeef} for a QString, i.e. the qstringdata address
  instead of the QString object itself.
  printq5string $s and printq5stringdata $s.d are equivalent.
end

define print_utf8_char
  set $uc = $arg0
  if ( $uc < 0x80 )
    printf "%c", (unsigned char)($uc & 0x7f)
  else
    if ( $uc < 0x0800 )
      printf "%c", (unsigned char)(0xc0 | ($uc >> 6))
    else
      printf "%c", (unsigned char)(0xe0 | ($uc >> 12)
      printf "%c", (unsigned char)(0x80 | (($uc > 6) &0x3f)
    end
    printf "%c", (unsigned char)(0x80 | ((uchar) $uc & 0x3f))
  end
end
document print_utf8_char
  Prints a unicode value (stored as an unsigned short) as UTF-8.
end

define printq4string_utf8
   set $i=0
   set $s = $arg0
   while $i < $s.d->size
     set $uc = (unsigned short) $s.d->data[$i++]
     print_utf8_char $uc
   end
   printf "\n"
end
document printq4string_utf8
  Prints the contents of a Qt4 QString encoded in utf8.
  Nice if you run your debug session in a utf8 enabled terminal.
end

define printq5string_utf8
   set $i=0
   set $s = $arg0
   set $d = $s.d
   set $data_char = (char*)$d + $d->offset
   set $data = (unsigned short*) $data_char
   set $size = $d->size
   while $i < $size
     print_utf8_char $data[$i++]
   end
   printf "\n"
end
document printq5string_utf8
  Prints the contents of a Qt5 QString encoded in utf8.
  Nice if you run your debug session in a utf8 enabled terminal.
end

define printqcstring
    print ($arg0).shd.data
    print ($arg0).shd.len
end
document printqcstring
  Prints the contents of a QCString (char * data, then length)
end

define printq4bytearray
    print ($arg0)->d->data
end
document printq4bytearray
  Prints the contents of a Qt4 QByteArray (when it contains a string)
end

define printqfont
    print *($arg0).d
    printqstring ($arg0).d->request.family
    print ($arg0).d->request.pointSize
end
document printqfont
  Prints the main attributes from a QFont, in particular the requested
  family and point size
end

define printqcolor
    printf "(%d,%d,%d)\n", ($arg0).red(), ($arg0).green(), ($arg0).blue()
end
document printqcolor
  Prints a QColor as (R,G,B).
  Usage: 'printqcolor <QColor col>
end

define printqmemarray
    # Maybe we could find it out the type by parsing "whatis $arg0"?
    set $arr = $arg0
    set $sz = sizeof($arg1)
    set $len = $arr->shd->len / $sz
    output $len
    printf " items in the array\n"
    set $i = 0
    while $i < $len
       # print "%s[%d] = %s\n", $arr, $i, *($arg1 *)(($arr->vec)[$i])
       print *($arg1 *)(($arr->shd->data) + ($i * $sz))
       set $i++
    end
end
document printqmemarray
  Prints the contents of a QMemArray. Pass the type as second argument.
end

define printqptrvector
    # Maybe we could find it out the type by parsing "whatis $arg0"?
    set $arr = $arg0
    set $len = $arr->len
    output $len
    printf " items in the vector\n"
    set $i = 0
    while $i < $len
       # print "%s[%d] = %s\n", $arr, $i, *($arg1 *)(($arr->vec)[$i])
       print *($arg1 *)(($arr->vec)[$i])
       set $i++
    end
end
document printqptrvector
  Prints the contents of a QPtrVector. Pass the type as second argument.
end

define printqptrvectoritem
    set $arr = $arg0
    set $i = $arg2
    print ($arg1 *)(($arr->vec)[$i])
    print *($arg1 *)(($arr->vec)[$i])
end
document printqptrvectoritem
  Print one item of a QPtrVector
  Usage: printqptrvectoritem vector type index
end

define printq4map
    set $map = $arg0
    set $len = $map.d->size
    output $len
    printf " items in the map\n"
    set $it = $map.e->forward[0]
    set $_qmap_end = $map.e
    ## Requires a process...
    set $_qmap_payload = $map->payload()
    while $it != $map.e
        set $_qmap_nodeaddress = (char*)($it) - $_qmap_payload
        set $_qmap_node = ('QMap<$arg1,$arg2>::Node' *)($_qmap_nodeaddress)
        printf " key="
        output $_qmap_node->key
        printf " value="
        output $_qmap_node->value
        printf "\n"
        # just in case the key and/or the value is a qstring, try printq4string on it
        # (if this is too noisy with other types, remove it, and use
        #  printq4stringdata on the shown d pointers instead, by hand)
        printq4string $_qmap_node->key
        printq4string $_qmap_node->value
        set $it = $it->forward[0]
    end
end
document printq4map
  Prints the full contents of a Qt 4 QMap
  Usage: 'printq4map map keytype valuetype'
end

define printqptrlist
    set $list = $arg0
    set $len = $list.numNodes
    output $len
    printf " items in the list\n"
    set $it = $list.firstNode
    while $it != 0
        output $it->data
        printf "\n"
        set $it = $it->next
    end
end
document printqptrlist
  Prints the contents of a QPtrList.
  Usage: printqptrlist mylist
end

define printqvaluelist
    set $list = $arg0
    set $len = $list.sh->nodes
    output $len
    printf " items in the list\n"
    set $it = $list.sh->node->next
    set $end = $list.sh->node
    while $it != $end
        output $it->data
        printf "\n"
        set $it = $it->next
    end
end
document printqvaluelist
  Prints the contents of a QValueList.
  Usage: printqvaluelist mylist
end

define printqstringlist
    set $list = $arg0
    set $len = $list.sh->nodes
    output $len
    printf " items in the list\n"
    set $it = $list.sh->node->next
    set $end = $list.sh->node
    while $it != $end
        printqstring $it->data
        set $it = $it->next
    end
end
document printqstringlist
  Prints the contents of a QStringList.
  Usage: printqstringlist mylist
end

define printqregion
    printqmemarray ($arg0).rects() QRect
end
document printqregion
  Prints the rectangles that make up a QRegion. Needs a running process.
  Usage: printqregion myregion
end

# Bad implementation, requires a running process.
# Needs to be refined, i.e. figuring out the right void* pointers casts.
# Simon says: each Node contains the d pointer of the QString.
define printq4stringlist
    # This is ugly, but we need to avoid conflicts with printq4string's own vars...
    set $q4sl_i = 0
    set $q4sl_d = & $arg0
    set $q4sl_sz = $q4sl_d->size()
    while $q4sl_i < $q4sl_sz
        output $q4sl_i
        printf " "
        printq4string $q4sl_d->at($q4sl_i++)
    end
end
document printq4stringlist
  Prints the contents of a Qt4 QStringList.
  Usage: printq4stringlist mylist
end

define identifyq4object
    set $obj=$arg0
    set $objectName=((QObjectPrivate *)($obj->d_ptr))->objectName
    printf " name:"
    printq4string $objectName
    printf " class:"
    # this requires a process, though
    print $obj->metaObject()->className()
end

# You print QString's too often to type the long name :-)
# Change when Qt6 is the default
define qs
  printq5string $arg0
end

define qs5
  printq5string $arg0
end

define qs4
  printq4string $arg0
end

define printqdatetime
  printqdate ($arg0).d
  printqtime ($arg0).t
end
document printqdatetime
  Prints a QDateTime
  Usage: printqdatetime myqdt
end
define printqdate
  printf "(Y:%d M:%d D:%d)\n", ($arg0).year(), ($arg0).month(), ($arg0).day()
end
document printqdate
  Prints a QDate
  Usage: printqdate mydate
end
define printqtime
  printf "(H:%d M:%d S:%d)\n", ($arg0).hour(), ($arg0).minute(), ($arg0).second()
end
document printqtime
  Prints a QTime
  Usage: printqtime mytime
end

# You are at f(g(h(i(), j(k(l())...) and you want to enter f: type fs <enter> <enter> <enter>
# fs=finish+step
define fs
       finish
       step
end
