def _parse_key(to_parse): """Parse key, value combination return (tuple): Number of characters parsed from to_parse Parsed key (string) """ if _DEBUG: print_red('key') print_red(to_parse) buf = '' i = 0 key = '' while i < len(to_parse) - 1: c = to_parse[i] if c == '=': key = buf # consume '=' sign so caller doesn't get it again i += 1 break buf += c i += 1 if _DEBUG: print_green(key) return i, key
def _parse_dict(to_parse): """Parse dictionary, with optional starting character '{' return (tuple): Number of characters parsed from to_parse Parsed dictionary """ if _DEBUG: print_red('obj') print_red(to_parse) i = 0 obj = {} while i < len(to_parse): c = to_parse[i] if c in _WHITESPACE: pass elif c in ['{', ',']: pass elif c == '}': # end of object, exit loop break else: chars_used, key, val = _parse_key_val(to_parse[i:]) i = i + chars_used obj[key] = val i += 1 if _DEBUG: print_green(obj) return i, obj
def _parse_str(to_parse): """Parse a string return (tuple): Number of characters parsed from to_parse Parsed string, without surrounding quotes """ # characters that gdb escapes that should not be # escaped by this parser CHARS_TO_REMOVE_GDB_ESCAPE = ['"'] if _DEBUG: print_red('string') print_red(to_parse) assert_match(_GDB_MI_CHAR_STRING_START, to_parse[0]) i = 1 # Skip the opening quote buf = '' while i < len(to_parse) - 1: c = to_parse[i] if _DEBUG: print_cyan(c) if c == '\\' and i < (len(to_parse) - 1): # We are on a backslash and there is another character after the backslash # to parse. Handle this case specially since gdb escaped it for us # Get the next char that is being escaped c2 = to_parse[i + 1] if c2 in CHARS_TO_REMOVE_GDB_ESCAPE: # only store the escaped character in the buffer; don't store the backslash # (don't leave it escaped) buf += to_parse[i + 1] else: # store the backslash and the following character in the buffer (leave it escaped) buf += c + to_parse[i + 1] # consume the backslash and the next character i += 2 else: # Quote is closed. Exit (and don't include the end quote). if c == '"': break buf += c i += 1 string = buf if _DEBUG: print_green(string) return i, string
def _parse_dict(to_parse): """Parse dictionary, with optional starting character '{' return (tuple): Number of characters parsed from to_parse Parsed dictionary """ if _DEBUG: print_red('obj') print_red(to_parse) i = 0 obj = {} while i < len(to_parse): c = to_parse[i] if c in _WHITESPACE: pass elif c in ['{', ',']: pass elif c == '}': # end of object, exit loop break else: chars_used, key, val = _parse_key_val(to_parse[i:]) i = i + chars_used 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) else: obj[key] = [obj[key], val] else: obj[key] = val i += 1 if _DEBUG: print_green(obj) return i, obj
def _parse_key_val(to_parse): """Parse key, value combination return (tuple): Number of characters parsed from to_parse Parsed key (string) Parsed value (either a string, array, or dict) """ if _DEBUG: print_red('keyval') print_red(to_parse) i = 0 size, key = _parse_key(to_parse[i:]) i += size size, val = _parse_val(to_parse[i:]) i += size if _DEBUG: print_green(key) print_green(val) return i, key, val
def _parse_val(to_parse): """Parse value from string return (tuple): Number of characters parsed from to_parse Parsed value (either a string, array, or dict) """ if _DEBUG: print_red('val') print_red(to_parse) i = 0 val = '' buf = '' while i < len(to_parse) - 1: c = to_parse[i] if c == '{': # Start object size, val = _parse_dict(to_parse[i:]) i += size break elif c == '[': # Start of an array size, val = _parse_array(to_parse[i:]) i += size break elif c == '"': # Start of a string size, val = _parse_str(to_parse[i:]) i += size break else: buf += c i += 1 if _DEBUG: print_green(val) return i, val
def _parse_array(to_parse): """Parse an array return (tuple): Number of characters parsed from to_parse Parsed array """ if _DEBUG: print_red('array') print_red(to_parse) assert_match(_GDB_MI_CHAR_ARRAY_START, to_parse[0]) # Skip first open bracket so we don't end up in an # endless loop trying to re-parse the array i = 1 arr = [] while i < len(to_parse) - 1: c = to_parse[i] if c in _GDB_MI_VALUE_START_CHARS: size, val = _parse_val(to_parse[i:]) arr.append(val) i += size 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 i += 1 if _DEBUG: print_green(arr) return i, arr