예제 #1
0
    def test_api(self):
        raw_text = 'abc- "d" ""ef"" g'
        stream = StringStream(raw_text)
        assert stream.index == 0
        assert stream.len == len(raw_text)

        buf = stream.read(1)
        assert_match(buf, "a")
        assert stream.index == 1

        stream.seek(-1)
        assert stream.index == 0

        buf = stream.advance_past_chars(['"'])
        buf = stream.advance_past_string_with_gdb_escapes()
        assert_match(buf, "d")

        buf = stream.advance_past_chars(['"'])
        buf = stream.advance_past_chars(['"'])
        buf = stream.advance_past_string_with_gdb_escapes()
        assert_match(buf, "ef")

        # read way past end to test it gracefully returns the
        # remainder of the string without failing
        buf = stream.read(50)
        assert_match(buf, '" g')
예제 #2
0
def _parse_dict(stream: StringStream):
    """Parse dictionary, with optional starting character '{'
    return (tuple):
        Number of characters parsed from to_parse
        Parsed dictionary
    """
    obj: Dict[str, Union[str, list]] = {}

    logger.debug("%s", fmt_green("parsing dict"))

    while True:
        c = stream.read(1)
        if c in _WHITESPACE:
            pass
        elif c in ["{", ","]:
            pass
        elif c in ["}", ""]:
            # end of object, exit loop
            break

        else:
            stream.seek(-1)
            key, val = _parse_key_val(stream)
            if key in obj:
                # This is a gdb bug. We should never get repeated keys in a dict!
                # See https://sourceware.org/bugzilla/show_bug.cgi?id=22217
                # and https://github.com/cs01/pygdbmi/issues/19
                # Example:
                #   thread-ids={thread-id="1",thread-id="2"}
                # Results in:
                #   thread-ids: {{'thread-id': ['1', '2']}}
                # Rather than the lossy
                #   thread-ids: {'thread-id': 2}  # '1' got overwritten!
                if isinstance(obj[key], list):
                    obj[key].append(val)  # type: ignore
                else:
                    obj[key] = [obj[key], val]
            else:
                obj[key] = val

            look_ahead_for_garbage = True
            c = stream.read(1)
            while look_ahead_for_garbage:
                if c in ["}", ",", ""]:
                    look_ahead_for_garbage = False
                else:
                    # got some garbage text, skip it. for example:
                    # name="gdb"gargage  # skip over 'garbage'
                    # name="gdb"\n  # skip over '\n'
                    logger.debug("skipping unexpected charcter: " + c)
                    c = stream.read(1)
            stream.seek(-1)

    logger.debug("parsed dict")
    logger.debug("%s", fmt_green(obj))
    return obj
예제 #3
0
def _parse_array(stream: StringStream):
    """Parse an array, stream should be passed the initial [
    returns:
        Parsed array
    """

    logger.debug("parsing array")
    arr = []
    while True:
        c = stream.read(1)

        if c in _GDB_MI_VALUE_START_CHARS:
            stream.seek(-1)
            val = _parse_val(stream)
            arr.append(val)
        elif c in _WHITESPACE:
            pass
        elif c == ",":
            pass
        elif c == "]":
            # Stop when this array has finished. Note
            # that elements of this array can be also be arrays.
            break

    logger.debug("parsed array:")
    logger.debug("%s", fmt_green(arr))
    return arr
예제 #4
0
def _parse_val(stream: StringStream):
    """Parse value from string
    returns:
        Parsed value (either a string, array, or dict)
    """

    logger.debug("parsing value")

    while True:
        c = stream.read(1)

        if c == "{":
            # Start object
            val = _parse_dict(stream)
            break

        elif c == "[":
            # Start of an array
            val = _parse_array(stream)
            break

        elif c == '"':
            # Start of a string
            val = stream.advance_past_string_with_gdb_escapes()
            break

        elif _DEBUG:
            raise ValueError("unexpected character: %s" % c)

        else:
            logger.warn(f'unexpected character: "{c}" ({ord(c)}). Continuing.')
            val = ""  # this will be overwritten if there are more characters to be read

    logger.debug("parsed value:")
    logger.debug("%s", fmt_green(val))

    return val