X-Git-Url: https://git.saurik.com/apple/xnu.git/blobdiff_plain/39236c6e673c41db228275375ab7fdb0f837b292..94ff46dc2849db4d43eaaf144872decc522aafb4:/tools/lldbmacros/core/standard.py diff --git a/tools/lldbmacros/core/standard.py b/tools/lldbmacros/core/standard.py old mode 100644 new mode 100755 index 547c49c21..9df6b7635 --- a/tools/lldbmacros/core/standard.py +++ b/tools/lldbmacros/core/standard.py @@ -4,7 +4,7 @@ import sys import re class ArgumentError(Exception): - """ Exception class for raising errors in command arguments. The lldb_command framework will catch this + """ Exception class for raising errors in command arguments. The lldb_command framework will catch this class of exceptions and print suitable error message to user. """ def __init__(self, msg): @@ -28,72 +28,199 @@ class RedirectStdStreams(object): sys.stdout = self.old_stdout sys.stderr = self.old_stderr +class IndentScope(object): + def __init__(self, O): + self._O = O + + def __enter__(self): + self._O._indent += ' ' + + def __exit__(self, exc_type, exc_value, traceback): + self._O._indent = self._O._indent[:-4] + +class HeaderScope(object): + def __init__(self, O, hdr, indent = False): + self._O = O + self._header = hdr + self._indent = indent + + def __enter__(self): + self._oldHeader = self._O._header + self._oldLastHeader = self._O._lastHeader + self._O._header = self._header + self._O._lastHeader = None + if self._indent: + self._O._indent += ' ' + + def __exit__(self, exc_type, exc_value, traceback): + self._O._header = self._oldHeader + self._O._lastHeader = self._oldLastHeader + if self._indent: + self._O._indent = self._O._indent[:-4] + +class VT(object): + Black = "\033[38;5;0m" + DarkRed = "\033[38;5;1m" + DarkGreen = "\033[38;5;2m" + Brown = "\033[38;5;3m" + DarkBlue = "\033[38;5;4m" + DarkMagenta = "\033[38;5;5m" + DarkCyan = "\033[38;5;6m" + Grey = "\033[38;5;7m" + + DarkGrey = "\033[38;5;8m" + Red = "\033[38;5;9m" + Green = "\033[38;5;10m" + Yellow = "\033[38;5;11m" + Blue = "\033[38;5;12m" + Magenta = "\033[38;5;13m" + Cyan = "\033[38;5;14m" + White = "\033[38;5;15m" + + Default = "\033[39m" + + Bold = "\033[1m" + EndBold = "\033[22m" + + Oblique = "\033[3m" + EndOblique = "\033[23m" + + Underline = "\033[4m" + EndUnderline = "\033[24m" + + Reset = "\033[0m" + +class NOVT(object): + def __getattribute__(self, *args): + return "" + class CommandOutput(object): """ - An output handler for all commands. Use Output.print to direct all output of macro via the handler. + An output handler for all commands. Use Output.print to direct all output of macro via the handler. These arguments are passed after a "--". eg (lldb) zprint -- -o /tmp/zprint.out.txt - - Currently this provide capabilities + + Currently this provide capabilities + -h show help -o path/to/filename - The output of this command execution will be saved to file. Parser information or errors will + The output of this command execution will be saved to file. Parser information or errors will not be sent to file though. eg /tmp/output.txt -s filter_string - the "filter_string" param is parsed to python regex expression and each line of output - will be printed/saved only if it matches the expression. + the "filter_string" param is parsed to python regex expression and each line of output + will be printed/saved only if it matches the expression. The command header will not be filtered in any case. + -p + Send the output of the command to plugin. + -v ... + Up verbosity + -c + configure color """ - def __init__(self, CommandResult): + def __init__(self, cmd_name, CommandResult=None, fhandle=None): """ Create a new instance to handle command output. params: - CommandResult : SBCommandReturnObject result param from lldb's command invocation. + CommandResult : SBCommandReturnObject result param from lldb's command invocation. """ self.fname=None - self.fhandle=None + self.fhandle=fhandle self.FILTER=False self.pluginRequired = False self.pluginName = None + self.cmd_name = cmd_name self.resultObj = CommandResult - self.immediateOutput = False self.verbose_level = 0 self.target_cmd_args = [] self.target_cmd_options = {} + self.color = None + self.isatty = os.isatty(sys.__stdout__.fileno()) + self._indent = '' + self._buffer = '' + + self._header = None + self._lastHeader = None + self._line = 0 + + def _write(self, s): + if self.fhandle != None: + self.fhandle.write(self._indent + s + "\n") + else: + self.resultObj.AppendMessage(self._indent + s) + self._line += 1 + + def _doColor(self): + if self.color is True: + return True; + return self.color is None and self.isatty + + def _needsHeader(self): + if self._header is None: + return False + if self._lastHeader is None: + return True + if not self.isatty: + return False + return self._line - self._lastHeader > 40 + + def indent(self): + return IndentScope(self) + + def table(self, header, indent = False): + return HeaderScope(self, header, indent) + + def format(self, s, *args, **kwargs): + if self._doColor(): + kwargs['VT'] = VT + else: + kwargs['VT'] = NOVT() + + return s.format(*args, **kwargs) + + def error(self, s, *args, **kwargs): + print self.format("{cmd.cmd_name}: {VT.Red}"+s+"{VT.Default}", cmd=self, *args, **kwargs) def write(self, s): """ Handler for all commands output. By default just print to stdout """ - if self.FILTER and not self.reg.search(s): return - if self.FILTER : s+="\n" - if self.fhandle != None: self.fhandle.write(s) - else: - if self.immediateOutput: - sys.__stdout__.write(s) - else: - res_str = s - if s.endswith("\n"): - res_str = s[:-1] - if self.resultObj and len(res_str) > 0: self.resultObj.AppendMessage(res_str) + + s = self._buffer + s + + while s.find('\n') != -1: + l, s = s.split("\n", 1) + if self.FILTER: + if not self.reg.search(l): + continue + if self._doColor(): + l = self.reg.sub(VT.Underline + r"\g<0>" + VT.EndUnderline, l); + + if len(l) and self._needsHeader(): + for hdr in self._header.split("\n"): + self._write(self.format("{VT.Bold}{:s}{VT.EndBold}", hdr)) + self._lastHeader = self._line + + self._write(l) + + self._buffer = s def flush(self): if self.fhandle != None: self.fhandle.flush() - + def __del__(self): """ closes any open files. report on any errors """ - if self.fhandle != None : + if self.fhandle != None and self.fname != None: self.fhandle.close() - - def setOptions(self,cmdargs, cmdoptions =''): - """ parse the arguments passed to the command - param : + + def setOptions(self, cmdargs, cmdoptions =''): + """ parse the arguments passed to the command + param : cmdargs => [] of (typically args.split()) - cmdoptions : str - string of command level options. + cmdoptions : str - string of command level options. These should be CAPITAL LETTER options only. """ opts=() args = cmdargs cmdoptions = cmdoptions.upper() try: - opts,args = getopt.gnu_getopt(args,'hvo:s:p:'+ cmdoptions,[]) + opts,args = getopt.gnu_getopt(args,'hvo:s:p:c:'+ cmdoptions,[]) self.target_cmd_args = args except getopt.GetoptError,err: raise ArgumentError(str(err)) @@ -107,6 +234,8 @@ class CommandOutput(object): self.fname=os.path.normpath(os.path.expanduser(a.strip())) self.fhandle=open(self.fname,"w") print "saving results in file ",str(a) + self.fhandle.write("(lldb)%s %s \n" % (self.cmd_name, " ".join(cmdargs))) + self.isatty = os.isatty(self.fhandle.fileno()) elif o == "-s" and len(a) > 0: self.reg = re.compile(a.strip(),re.MULTILINE|re.DOTALL) self.FILTER=True @@ -115,12 +244,17 @@ class CommandOutput(object): self.pluginRequired = True self.pluginName = a.strip() #print "passing output to " + a.strip() - elif o == "-v" : + elif o == "-v": self.verbose_level += 1 + elif o == "-c": + if a in ["always", '1']: + self.color = True + elif a in ["never", '0']: + self.color = False + else: + self.color = None else: o = o.strip() self.target_cmd_options[o] = a - -