blob: f294d20437a83540de7ea7c3a4b57392ab410eb1 [file] [log] [blame]
# 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.
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])