mirror of
https://github.com/tstack/lnav
synced 2024-11-05 21:21:19 +00:00
250 lines
7.4 KiB
Python
Executable File
250 lines
7.4 KiB
Python
Executable File
#! /usr/bin/env python
|
|
|
|
# Copyright (c) 2013, Timothy Stack
|
|
#
|
|
# All rights reserved.
|
|
#
|
|
# Redistribution and use in source and binary forms, with or without
|
|
# modification, are permitted provided that the following conditions are met:
|
|
#
|
|
# * Redistributions of source code must retain the above copyright notice, this
|
|
# list of conditions and the following disclaimer.
|
|
# * Redistributions in binary form must reproduce the above copyright notice,
|
|
# this list of conditions and the following disclaimer in the documentation
|
|
# and/or other materials provided with the distribution.
|
|
# * Neither the name of Timothy Stack nor the names of its contributors
|
|
# may be used to endorse or promote products derived from this software
|
|
# without specific prior written permission.
|
|
#
|
|
# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ''AS IS'' AND ANY
|
|
# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
# DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
|
# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
|
# ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
|
|
import os
|
|
import string
|
|
import readline
|
|
import itertools
|
|
import collections
|
|
|
|
TEST_DIR = os.path.dirname(__file__)
|
|
ROOT_DIR = os.path.dirname(TEST_DIR)
|
|
SRC_DIR = os.path.join(ROOT_DIR, "src")
|
|
|
|
addr_to_name = {}
|
|
name_to_addr = {}
|
|
element_lists = collections.defaultdict(list)
|
|
list_depth = {}
|
|
list_format = {}
|
|
breakpoints = set()
|
|
|
|
def completer(text, state):
|
|
options = [x for x in itertools.chain(name_to_addr,
|
|
element_lists,
|
|
breakpoints)
|
|
if x.startswith(text)]
|
|
try:
|
|
return options[state]
|
|
except IndexError:
|
|
return None
|
|
|
|
readline.set_completer(completer)
|
|
|
|
if 'libedit' in readline.__doc__:
|
|
readline.parse_and_bind('bind ^I rl_complete')
|
|
else:
|
|
readline.parse_and_bind('tab: complete')
|
|
|
|
input_line = ''
|
|
ops = []
|
|
for line in open("scanned.dpt"):
|
|
if line.startswith("input "):
|
|
input_line = line[6:-1]
|
|
else:
|
|
ops.append(map(string.strip, line.split()))
|
|
|
|
def getstr(capture):
|
|
start, end = capture.split(':')
|
|
return input_line[int(start):int(end)]
|
|
|
|
def printlist(name_or_addr):
|
|
if name_or_addr in name_to_addr:
|
|
addr = name_to_addr[name_or_addr]
|
|
print "% 3d (%s:%s) %s" % (list_depth.get(addr, -1), name_or_addr, addr, element_lists[addr])
|
|
elif name_or_addr in element_lists:
|
|
addr = name_or_addr
|
|
print "% 3d (%s:%s) %s" % (list_depth.get(name_or_addr, -1),
|
|
addr_to_name.get(name_or_addr, name_or_addr),
|
|
name_or_addr,
|
|
element_lists[name_or_addr])
|
|
else:
|
|
print "error: unknown list --", name_or_addr
|
|
|
|
if addr in list_format:
|
|
print " format -- appender(%s) term(%s) qual(%s) sep(%s) prefix_term(%s)" % tuple(list_format[addr])
|
|
|
|
def handleop(fields):
|
|
addr = fields[0]
|
|
loc = fields[1].split(':')
|
|
method_name = fields[2]
|
|
method_args = fields[3:]
|
|
|
|
if addr == '0x0':
|
|
el = None
|
|
else:
|
|
el = element_lists[addr]
|
|
|
|
if method_name == 'element_list_t':
|
|
addr_to_name[addr] = method_args[0]
|
|
name_to_addr[method_args[0]] = addr
|
|
list_depth[addr] = int(method_args[1])
|
|
elif method_name == '~element_list_t':
|
|
del element_lists[addr]
|
|
elif method_name == 'format':
|
|
list_depth[addr] = int(method_args[0])
|
|
list_format[addr] = method_args[1:]
|
|
elif method_name == 'consumed':
|
|
list_depth[addr] = -1
|
|
elif method_name == 'push_back':
|
|
el.append((method_args[0], getstr(method_args[1])))
|
|
elif method_name == 'pop_front':
|
|
el.pop(0)
|
|
elif method_name == 'pop_back':
|
|
el.pop()
|
|
elif method_name == 'clear2':
|
|
el[::] = []
|
|
elif method_name == 'splice':
|
|
pos = int(method_args[0])
|
|
other = element_lists[method_args[1]]
|
|
start, from_end = map(int, method_args[2].split(':'))
|
|
end = len(other) - from_end
|
|
sub_list = other[start:end]
|
|
del other[start:end]
|
|
el[pos:pos] = sub_list
|
|
elif method_name == 'swap':
|
|
other = element_lists[method_args[0]]
|
|
element_lists[method_args[0]] = el
|
|
element_lists[addr] = other
|
|
elif method_name == 'point':
|
|
breakpoints.add(method_args[0])
|
|
else:
|
|
print "Unhandled method: ", method_name
|
|
|
|
def playupto(length):
|
|
addr_to_name.clear()
|
|
name_to_addr.clear()
|
|
element_lists.clear()
|
|
list_depth.clear()
|
|
for index in range(length):
|
|
handleop(ops[index])
|
|
|
|
def find_prev_point(start, name):
|
|
orig_start = start
|
|
while start > 0:
|
|
start -= 1;
|
|
fields = ops[start]
|
|
if fields[2] != 'point':
|
|
continue
|
|
if not name or fields[3] == name:
|
|
return start + 1
|
|
return orig_start + 1
|
|
|
|
def find_next_point(start, name):
|
|
orig_start = start
|
|
while start < len(ops):
|
|
start += 1;
|
|
fields = ops[start]
|
|
if fields[2] != 'point':
|
|
continue
|
|
if not name or fields[3] == name:
|
|
return start + 1
|
|
return orig_start + 1
|
|
|
|
def printall():
|
|
print input_line
|
|
sorted_lists = [(list_depth.get(addr, -1), addr) for addr in element_lists]
|
|
sorted_lists.sort()
|
|
for _depth, addr in sorted_lists:
|
|
printlist(addr)
|
|
|
|
index = len(ops)
|
|
last_cmd = ['']
|
|
watch_list = set()
|
|
while True:
|
|
playupto(index)
|
|
|
|
if index == 0:
|
|
print "init"
|
|
else:
|
|
op = ops[index - 1]
|
|
print "#%s %s" % (index -1, op)
|
|
if op[2] == 'push_back':
|
|
print getstr(op[4])
|
|
|
|
for list_name in watch_list:
|
|
printlist(list_name)
|
|
|
|
try:
|
|
cmd = raw_input("> ").split()
|
|
except EOFError:
|
|
print
|
|
break
|
|
|
|
if not cmd or cmd[0] == '':
|
|
cmd = last_cmd
|
|
|
|
if not cmd or cmd[0] == '':
|
|
pass
|
|
elif cmd[0] == 'h':
|
|
print 'Help:'
|
|
print ' q - quit'
|
|
print ' s - Start over'
|
|
print ' n - Next step'
|
|
print ' r - Previous step'
|
|
print ' b - Previous breakpoint'
|
|
print ' c - Next breakpoint'
|
|
print ' p - Print state'
|
|
print ' w <var> - Add a variable to the watch list'
|
|
print ' u <var> - Remove a variable from the watch list'
|
|
elif cmd[0] == 'q':
|
|
break
|
|
elif cmd[0] == 's':
|
|
index = 0
|
|
elif cmd[0] == 'n':
|
|
if index < len(ops):
|
|
index += 1
|
|
elif cmd[0] == 'r':
|
|
if index > 0:
|
|
index -= 1
|
|
elif cmd[0] == 'b':
|
|
if len(cmd) == 1:
|
|
cmd.append('')
|
|
|
|
index = find_prev_point(index - 1, cmd[1])
|
|
elif cmd[0] == 'c':
|
|
if len(cmd) == 1:
|
|
cmd.append('')
|
|
index = find_next_point(index - 1, cmd[1])
|
|
elif cmd[0] == 'p':
|
|
if len(cmd) > 1:
|
|
printlist(cmd[1])
|
|
else:
|
|
printall()
|
|
elif cmd[0] == 'w':
|
|
watch_list.add(cmd[1])
|
|
elif cmd[0] == 'u':
|
|
if watch_list:
|
|
watch_list.remove(cmd[1])
|
|
else:
|
|
print "error: unknown command --", cmd
|
|
|
|
printall()
|
|
|
|
last_cmd = cmd
|