# Copyright (c) 2019 The Regents of the University of California # 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 the copyright holders 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 COPYRIGHT HOLDERS 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 COPYRIGHT # OWNER 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. # # Authors: Bobby R. Bruce import textwrap class TerminalFormatter: def __init__(self, max_width=80): # text_width holds the actual width we'll be wrapping to. # This takes into account the current terminal size. self.__text_width = min(max_width, self.__terminal_size()[0]) def __terminal_size(self): import fcntl, termios, struct h, w, hp, wp = struct.unpack('HHHH', fcntl.ioctl(0, termios.TIOCGWINSZ, struct.pack('HHHH', 0, 0, 0, 0))) return w, h def __get_paragraphs(self, text, flatten=False): """ This function takes a text and returns a list of constituent paragraphs, defining a paragraph as a block of text separated from other text by a blank line (or one containing only whitespace). If the "flatten" argument is set to true, all line breaks within paragraphs will be removed. E.g.: text = '''Hello, this is paragraph number 1. This is paragraph number 2. And this is paragraph number 3. ''' __get_paragraphs(text, False) ["Hello, this is\nparagraph number 1", "This is paragraph number 2.", "And this is\npagraph number 3."] __get_paragraphs(text, True) ["Hello, this is paragraph number 1", "This is paragraph number 2.", "And this is pagraph number 3."] """ paragraphs = [] cur_paragraph = [] for line in text.splitlines(): stripped = line.strip() if not stripped: #I.e. a blank line. paragraphs.append( {False: "\n", True: " "}[flatten].join(cur_paragraph)) cur_paragraph = [] else: cur_paragraph.append(stripped) paragraphs.append( {False: "\n", True: " "}[flatten].join(cur_paragraph)) return paragraphs def format_output(self, text, label="", indent=0): """ This function aids in the formatting of outputs. When obtaining the list of sim object we desire the output in the following format: desc: Address to mask loading binaries with, if 0, system auto-calculates the mask to be the most restrictive, otherwise it obeys a custom mask. We must take into account the width of the text, and wrap accordingly. We also must display the label. Keyword arguments: text --- The description text. label --- The label of the output (e.g. "desc: "). indent --- The white space width before each line. """ if not text.strip(): return "" # The text may be over multiple lines (as when using triple # double quotes). First, we split the text into its constituent # paragraphs and remove new line characters from each. paragraphs = self.__get_paragraphs(text, True) # Wrap and Indent the paragraphs wrapper = textwrap.TextWrapper(width = max((self.__text_width - indent),1)) # The first paragraph is special case due to the inclusion of the label formatted_paragraphs = [' ' * max((indent - len(label)),0) \ + label + wrapper.wrap(paragraphs[0])[0]] for paragraph in paragraphs: for line in wrapper.wrap(paragraph[1:])[1:]: formatted_paragraphs.append(' ' * indent + line) formatted_paragraphs.append('\n') # Remove the last line break return '\n'.join(formatted_paragraphs[:-1])