17db96d56Sopenharmony_ci"""A generic class to build line-oriented command interpreters. 27db96d56Sopenharmony_ci 37db96d56Sopenharmony_ciInterpreters constructed with this class obey the following conventions: 47db96d56Sopenharmony_ci 57db96d56Sopenharmony_ci1. End of file on input is processed as the command 'EOF'. 67db96d56Sopenharmony_ci2. A command is parsed out of each line by collecting the prefix composed 77db96d56Sopenharmony_ci of characters in the identchars member. 87db96d56Sopenharmony_ci3. A command `foo' is dispatched to a method 'do_foo()'; the do_ method 97db96d56Sopenharmony_ci is passed a single argument consisting of the remainder of the line. 107db96d56Sopenharmony_ci4. Typing an empty line repeats the last command. (Actually, it calls the 117db96d56Sopenharmony_ci method `emptyline', which may be overridden in a subclass.) 127db96d56Sopenharmony_ci5. There is a predefined `help' method. Given an argument `topic', it 137db96d56Sopenharmony_ci calls the command `help_topic'. With no arguments, it lists all topics 147db96d56Sopenharmony_ci with defined help_ functions, broken into up to three topics; documented 157db96d56Sopenharmony_ci commands, miscellaneous help topics, and undocumented commands. 167db96d56Sopenharmony_ci6. The command '?' is a synonym for `help'. The command '!' is a synonym 177db96d56Sopenharmony_ci for `shell', if a do_shell method exists. 187db96d56Sopenharmony_ci7. If completion is enabled, completing commands will be done automatically, 197db96d56Sopenharmony_ci and completing of commands args is done by calling complete_foo() with 207db96d56Sopenharmony_ci arguments text, line, begidx, endidx. text is string we are matching 217db96d56Sopenharmony_ci against, all returned matches must begin with it. line is the current 227db96d56Sopenharmony_ci input line (lstripped), begidx and endidx are the beginning and end 237db96d56Sopenharmony_ci indexes of the text being matched, which could be used to provide 247db96d56Sopenharmony_ci different completion depending upon which position the argument is in. 257db96d56Sopenharmony_ci 267db96d56Sopenharmony_ciThe `default' method may be overridden to intercept commands for which there 277db96d56Sopenharmony_ciis no do_ method. 287db96d56Sopenharmony_ci 297db96d56Sopenharmony_ciThe `completedefault' method may be overridden to intercept completions for 307db96d56Sopenharmony_cicommands that have no complete_ method. 317db96d56Sopenharmony_ci 327db96d56Sopenharmony_ciThe data member `self.ruler' sets the character used to draw separator lines 337db96d56Sopenharmony_ciin the help messages. If empty, no ruler line is drawn. It defaults to "=". 347db96d56Sopenharmony_ci 357db96d56Sopenharmony_ciIf the value of `self.intro' is nonempty when the cmdloop method is called, 367db96d56Sopenharmony_ciit is printed out on interpreter startup. This value may be overridden 377db96d56Sopenharmony_civia an optional argument to the cmdloop() method. 387db96d56Sopenharmony_ci 397db96d56Sopenharmony_ciThe data members `self.doc_header', `self.misc_header', and 407db96d56Sopenharmony_ci`self.undoc_header' set the headers used for the help function's 417db96d56Sopenharmony_cilistings of documented functions, miscellaneous topics, and undocumented 427db96d56Sopenharmony_cifunctions respectively. 437db96d56Sopenharmony_ci""" 447db96d56Sopenharmony_ci 457db96d56Sopenharmony_ciimport string, sys 467db96d56Sopenharmony_ci 477db96d56Sopenharmony_ci__all__ = ["Cmd"] 487db96d56Sopenharmony_ci 497db96d56Sopenharmony_ciPROMPT = '(Cmd) ' 507db96d56Sopenharmony_ciIDENTCHARS = string.ascii_letters + string.digits + '_' 517db96d56Sopenharmony_ci 527db96d56Sopenharmony_ciclass Cmd: 537db96d56Sopenharmony_ci """A simple framework for writing line-oriented command interpreters. 547db96d56Sopenharmony_ci 557db96d56Sopenharmony_ci These are often useful for test harnesses, administrative tools, and 567db96d56Sopenharmony_ci prototypes that will later be wrapped in a more sophisticated interface. 577db96d56Sopenharmony_ci 587db96d56Sopenharmony_ci A Cmd instance or subclass instance is a line-oriented interpreter 597db96d56Sopenharmony_ci framework. There is no good reason to instantiate Cmd itself; rather, 607db96d56Sopenharmony_ci it's useful as a superclass of an interpreter class you define yourself 617db96d56Sopenharmony_ci in order to inherit Cmd's methods and encapsulate action methods. 627db96d56Sopenharmony_ci 637db96d56Sopenharmony_ci """ 647db96d56Sopenharmony_ci prompt = PROMPT 657db96d56Sopenharmony_ci identchars = IDENTCHARS 667db96d56Sopenharmony_ci ruler = '=' 677db96d56Sopenharmony_ci lastcmd = '' 687db96d56Sopenharmony_ci intro = None 697db96d56Sopenharmony_ci doc_leader = "" 707db96d56Sopenharmony_ci doc_header = "Documented commands (type help <topic>):" 717db96d56Sopenharmony_ci misc_header = "Miscellaneous help topics:" 727db96d56Sopenharmony_ci undoc_header = "Undocumented commands:" 737db96d56Sopenharmony_ci nohelp = "*** No help on %s" 747db96d56Sopenharmony_ci use_rawinput = 1 757db96d56Sopenharmony_ci 767db96d56Sopenharmony_ci def __init__(self, completekey='tab', stdin=None, stdout=None): 777db96d56Sopenharmony_ci """Instantiate a line-oriented interpreter framework. 787db96d56Sopenharmony_ci 797db96d56Sopenharmony_ci The optional argument 'completekey' is the readline name of a 807db96d56Sopenharmony_ci completion key; it defaults to the Tab key. If completekey is 817db96d56Sopenharmony_ci not None and the readline module is available, command completion 827db96d56Sopenharmony_ci is done automatically. The optional arguments stdin and stdout 837db96d56Sopenharmony_ci specify alternate input and output file objects; if not specified, 847db96d56Sopenharmony_ci sys.stdin and sys.stdout are used. 857db96d56Sopenharmony_ci 867db96d56Sopenharmony_ci """ 877db96d56Sopenharmony_ci if stdin is not None: 887db96d56Sopenharmony_ci self.stdin = stdin 897db96d56Sopenharmony_ci else: 907db96d56Sopenharmony_ci self.stdin = sys.stdin 917db96d56Sopenharmony_ci if stdout is not None: 927db96d56Sopenharmony_ci self.stdout = stdout 937db96d56Sopenharmony_ci else: 947db96d56Sopenharmony_ci self.stdout = sys.stdout 957db96d56Sopenharmony_ci self.cmdqueue = [] 967db96d56Sopenharmony_ci self.completekey = completekey 977db96d56Sopenharmony_ci 987db96d56Sopenharmony_ci def cmdloop(self, intro=None): 997db96d56Sopenharmony_ci """Repeatedly issue a prompt, accept input, parse an initial prefix 1007db96d56Sopenharmony_ci off the received input, and dispatch to action methods, passing them 1017db96d56Sopenharmony_ci the remainder of the line as argument. 1027db96d56Sopenharmony_ci 1037db96d56Sopenharmony_ci """ 1047db96d56Sopenharmony_ci 1057db96d56Sopenharmony_ci self.preloop() 1067db96d56Sopenharmony_ci if self.use_rawinput and self.completekey: 1077db96d56Sopenharmony_ci try: 1087db96d56Sopenharmony_ci import readline 1097db96d56Sopenharmony_ci self.old_completer = readline.get_completer() 1107db96d56Sopenharmony_ci readline.set_completer(self.complete) 1117db96d56Sopenharmony_ci readline.parse_and_bind(self.completekey+": complete") 1127db96d56Sopenharmony_ci except ImportError: 1137db96d56Sopenharmony_ci pass 1147db96d56Sopenharmony_ci try: 1157db96d56Sopenharmony_ci if intro is not None: 1167db96d56Sopenharmony_ci self.intro = intro 1177db96d56Sopenharmony_ci if self.intro: 1187db96d56Sopenharmony_ci self.stdout.write(str(self.intro)+"\n") 1197db96d56Sopenharmony_ci stop = None 1207db96d56Sopenharmony_ci while not stop: 1217db96d56Sopenharmony_ci if self.cmdqueue: 1227db96d56Sopenharmony_ci line = self.cmdqueue.pop(0) 1237db96d56Sopenharmony_ci else: 1247db96d56Sopenharmony_ci if self.use_rawinput: 1257db96d56Sopenharmony_ci try: 1267db96d56Sopenharmony_ci line = input(self.prompt) 1277db96d56Sopenharmony_ci except EOFError: 1287db96d56Sopenharmony_ci line = 'EOF' 1297db96d56Sopenharmony_ci else: 1307db96d56Sopenharmony_ci self.stdout.write(self.prompt) 1317db96d56Sopenharmony_ci self.stdout.flush() 1327db96d56Sopenharmony_ci line = self.stdin.readline() 1337db96d56Sopenharmony_ci if not len(line): 1347db96d56Sopenharmony_ci line = 'EOF' 1357db96d56Sopenharmony_ci else: 1367db96d56Sopenharmony_ci line = line.rstrip('\r\n') 1377db96d56Sopenharmony_ci line = self.precmd(line) 1387db96d56Sopenharmony_ci stop = self.onecmd(line) 1397db96d56Sopenharmony_ci stop = self.postcmd(stop, line) 1407db96d56Sopenharmony_ci self.postloop() 1417db96d56Sopenharmony_ci finally: 1427db96d56Sopenharmony_ci if self.use_rawinput and self.completekey: 1437db96d56Sopenharmony_ci try: 1447db96d56Sopenharmony_ci import readline 1457db96d56Sopenharmony_ci readline.set_completer(self.old_completer) 1467db96d56Sopenharmony_ci except ImportError: 1477db96d56Sopenharmony_ci pass 1487db96d56Sopenharmony_ci 1497db96d56Sopenharmony_ci 1507db96d56Sopenharmony_ci def precmd(self, line): 1517db96d56Sopenharmony_ci """Hook method executed just before the command line is 1527db96d56Sopenharmony_ci interpreted, but after the input prompt is generated and issued. 1537db96d56Sopenharmony_ci 1547db96d56Sopenharmony_ci """ 1557db96d56Sopenharmony_ci return line 1567db96d56Sopenharmony_ci 1577db96d56Sopenharmony_ci def postcmd(self, stop, line): 1587db96d56Sopenharmony_ci """Hook method executed just after a command dispatch is finished.""" 1597db96d56Sopenharmony_ci return stop 1607db96d56Sopenharmony_ci 1617db96d56Sopenharmony_ci def preloop(self): 1627db96d56Sopenharmony_ci """Hook method executed once when the cmdloop() method is called.""" 1637db96d56Sopenharmony_ci pass 1647db96d56Sopenharmony_ci 1657db96d56Sopenharmony_ci def postloop(self): 1667db96d56Sopenharmony_ci """Hook method executed once when the cmdloop() method is about to 1677db96d56Sopenharmony_ci return. 1687db96d56Sopenharmony_ci 1697db96d56Sopenharmony_ci """ 1707db96d56Sopenharmony_ci pass 1717db96d56Sopenharmony_ci 1727db96d56Sopenharmony_ci def parseline(self, line): 1737db96d56Sopenharmony_ci """Parse the line into a command name and a string containing 1747db96d56Sopenharmony_ci the arguments. Returns a tuple containing (command, args, line). 1757db96d56Sopenharmony_ci 'command' and 'args' may be None if the line couldn't be parsed. 1767db96d56Sopenharmony_ci """ 1777db96d56Sopenharmony_ci line = line.strip() 1787db96d56Sopenharmony_ci if not line: 1797db96d56Sopenharmony_ci return None, None, line 1807db96d56Sopenharmony_ci elif line[0] == '?': 1817db96d56Sopenharmony_ci line = 'help ' + line[1:] 1827db96d56Sopenharmony_ci elif line[0] == '!': 1837db96d56Sopenharmony_ci if hasattr(self, 'do_shell'): 1847db96d56Sopenharmony_ci line = 'shell ' + line[1:] 1857db96d56Sopenharmony_ci else: 1867db96d56Sopenharmony_ci return None, None, line 1877db96d56Sopenharmony_ci i, n = 0, len(line) 1887db96d56Sopenharmony_ci while i < n and line[i] in self.identchars: i = i+1 1897db96d56Sopenharmony_ci cmd, arg = line[:i], line[i:].strip() 1907db96d56Sopenharmony_ci return cmd, arg, line 1917db96d56Sopenharmony_ci 1927db96d56Sopenharmony_ci def onecmd(self, line): 1937db96d56Sopenharmony_ci """Interpret the argument as though it had been typed in response 1947db96d56Sopenharmony_ci to the prompt. 1957db96d56Sopenharmony_ci 1967db96d56Sopenharmony_ci This may be overridden, but should not normally need to be; 1977db96d56Sopenharmony_ci see the precmd() and postcmd() methods for useful execution hooks. 1987db96d56Sopenharmony_ci The return value is a flag indicating whether interpretation of 1997db96d56Sopenharmony_ci commands by the interpreter should stop. 2007db96d56Sopenharmony_ci 2017db96d56Sopenharmony_ci """ 2027db96d56Sopenharmony_ci cmd, arg, line = self.parseline(line) 2037db96d56Sopenharmony_ci if not line: 2047db96d56Sopenharmony_ci return self.emptyline() 2057db96d56Sopenharmony_ci if cmd is None: 2067db96d56Sopenharmony_ci return self.default(line) 2077db96d56Sopenharmony_ci self.lastcmd = line 2087db96d56Sopenharmony_ci if line == 'EOF' : 2097db96d56Sopenharmony_ci self.lastcmd = '' 2107db96d56Sopenharmony_ci if cmd == '': 2117db96d56Sopenharmony_ci return self.default(line) 2127db96d56Sopenharmony_ci else: 2137db96d56Sopenharmony_ci try: 2147db96d56Sopenharmony_ci func = getattr(self, 'do_' + cmd) 2157db96d56Sopenharmony_ci except AttributeError: 2167db96d56Sopenharmony_ci return self.default(line) 2177db96d56Sopenharmony_ci return func(arg) 2187db96d56Sopenharmony_ci 2197db96d56Sopenharmony_ci def emptyline(self): 2207db96d56Sopenharmony_ci """Called when an empty line is entered in response to the prompt. 2217db96d56Sopenharmony_ci 2227db96d56Sopenharmony_ci If this method is not overridden, it repeats the last nonempty 2237db96d56Sopenharmony_ci command entered. 2247db96d56Sopenharmony_ci 2257db96d56Sopenharmony_ci """ 2267db96d56Sopenharmony_ci if self.lastcmd: 2277db96d56Sopenharmony_ci return self.onecmd(self.lastcmd) 2287db96d56Sopenharmony_ci 2297db96d56Sopenharmony_ci def default(self, line): 2307db96d56Sopenharmony_ci """Called on an input line when the command prefix is not recognized. 2317db96d56Sopenharmony_ci 2327db96d56Sopenharmony_ci If this method is not overridden, it prints an error message and 2337db96d56Sopenharmony_ci returns. 2347db96d56Sopenharmony_ci 2357db96d56Sopenharmony_ci """ 2367db96d56Sopenharmony_ci self.stdout.write('*** Unknown syntax: %s\n'%line) 2377db96d56Sopenharmony_ci 2387db96d56Sopenharmony_ci def completedefault(self, *ignored): 2397db96d56Sopenharmony_ci """Method called to complete an input line when no command-specific 2407db96d56Sopenharmony_ci complete_*() method is available. 2417db96d56Sopenharmony_ci 2427db96d56Sopenharmony_ci By default, it returns an empty list. 2437db96d56Sopenharmony_ci 2447db96d56Sopenharmony_ci """ 2457db96d56Sopenharmony_ci return [] 2467db96d56Sopenharmony_ci 2477db96d56Sopenharmony_ci def completenames(self, text, *ignored): 2487db96d56Sopenharmony_ci dotext = 'do_'+text 2497db96d56Sopenharmony_ci return [a[3:] for a in self.get_names() if a.startswith(dotext)] 2507db96d56Sopenharmony_ci 2517db96d56Sopenharmony_ci def complete(self, text, state): 2527db96d56Sopenharmony_ci """Return the next possible completion for 'text'. 2537db96d56Sopenharmony_ci 2547db96d56Sopenharmony_ci If a command has not been entered, then complete against command list. 2557db96d56Sopenharmony_ci Otherwise try to call complete_<command> to get list of completions. 2567db96d56Sopenharmony_ci """ 2577db96d56Sopenharmony_ci if state == 0: 2587db96d56Sopenharmony_ci import readline 2597db96d56Sopenharmony_ci origline = readline.get_line_buffer() 2607db96d56Sopenharmony_ci line = origline.lstrip() 2617db96d56Sopenharmony_ci stripped = len(origline) - len(line) 2627db96d56Sopenharmony_ci begidx = readline.get_begidx() - stripped 2637db96d56Sopenharmony_ci endidx = readline.get_endidx() - stripped 2647db96d56Sopenharmony_ci if begidx>0: 2657db96d56Sopenharmony_ci cmd, args, foo = self.parseline(line) 2667db96d56Sopenharmony_ci if cmd == '': 2677db96d56Sopenharmony_ci compfunc = self.completedefault 2687db96d56Sopenharmony_ci else: 2697db96d56Sopenharmony_ci try: 2707db96d56Sopenharmony_ci compfunc = getattr(self, 'complete_' + cmd) 2717db96d56Sopenharmony_ci except AttributeError: 2727db96d56Sopenharmony_ci compfunc = self.completedefault 2737db96d56Sopenharmony_ci else: 2747db96d56Sopenharmony_ci compfunc = self.completenames 2757db96d56Sopenharmony_ci self.completion_matches = compfunc(text, line, begidx, endidx) 2767db96d56Sopenharmony_ci try: 2777db96d56Sopenharmony_ci return self.completion_matches[state] 2787db96d56Sopenharmony_ci except IndexError: 2797db96d56Sopenharmony_ci return None 2807db96d56Sopenharmony_ci 2817db96d56Sopenharmony_ci def get_names(self): 2827db96d56Sopenharmony_ci # This method used to pull in base class attributes 2837db96d56Sopenharmony_ci # at a time dir() didn't do it yet. 2847db96d56Sopenharmony_ci return dir(self.__class__) 2857db96d56Sopenharmony_ci 2867db96d56Sopenharmony_ci def complete_help(self, *args): 2877db96d56Sopenharmony_ci commands = set(self.completenames(*args)) 2887db96d56Sopenharmony_ci topics = set(a[5:] for a in self.get_names() 2897db96d56Sopenharmony_ci if a.startswith('help_' + args[0])) 2907db96d56Sopenharmony_ci return list(commands | topics) 2917db96d56Sopenharmony_ci 2927db96d56Sopenharmony_ci def do_help(self, arg): 2937db96d56Sopenharmony_ci 'List available commands with "help" or detailed help with "help cmd".' 2947db96d56Sopenharmony_ci if arg: 2957db96d56Sopenharmony_ci # XXX check arg syntax 2967db96d56Sopenharmony_ci try: 2977db96d56Sopenharmony_ci func = getattr(self, 'help_' + arg) 2987db96d56Sopenharmony_ci except AttributeError: 2997db96d56Sopenharmony_ci try: 3007db96d56Sopenharmony_ci doc=getattr(self, 'do_' + arg).__doc__ 3017db96d56Sopenharmony_ci if doc: 3027db96d56Sopenharmony_ci self.stdout.write("%s\n"%str(doc)) 3037db96d56Sopenharmony_ci return 3047db96d56Sopenharmony_ci except AttributeError: 3057db96d56Sopenharmony_ci pass 3067db96d56Sopenharmony_ci self.stdout.write("%s\n"%str(self.nohelp % (arg,))) 3077db96d56Sopenharmony_ci return 3087db96d56Sopenharmony_ci func() 3097db96d56Sopenharmony_ci else: 3107db96d56Sopenharmony_ci names = self.get_names() 3117db96d56Sopenharmony_ci cmds_doc = [] 3127db96d56Sopenharmony_ci cmds_undoc = [] 3137db96d56Sopenharmony_ci topics = set() 3147db96d56Sopenharmony_ci for name in names: 3157db96d56Sopenharmony_ci if name[:5] == 'help_': 3167db96d56Sopenharmony_ci topics.add(name[5:]) 3177db96d56Sopenharmony_ci names.sort() 3187db96d56Sopenharmony_ci # There can be duplicates if routines overridden 3197db96d56Sopenharmony_ci prevname = '' 3207db96d56Sopenharmony_ci for name in names: 3217db96d56Sopenharmony_ci if name[:3] == 'do_': 3227db96d56Sopenharmony_ci if name == prevname: 3237db96d56Sopenharmony_ci continue 3247db96d56Sopenharmony_ci prevname = name 3257db96d56Sopenharmony_ci cmd=name[3:] 3267db96d56Sopenharmony_ci if cmd in topics: 3277db96d56Sopenharmony_ci cmds_doc.append(cmd) 3287db96d56Sopenharmony_ci topics.remove(cmd) 3297db96d56Sopenharmony_ci elif getattr(self, name).__doc__: 3307db96d56Sopenharmony_ci cmds_doc.append(cmd) 3317db96d56Sopenharmony_ci else: 3327db96d56Sopenharmony_ci cmds_undoc.append(cmd) 3337db96d56Sopenharmony_ci self.stdout.write("%s\n"%str(self.doc_leader)) 3347db96d56Sopenharmony_ci self.print_topics(self.doc_header, cmds_doc, 15,80) 3357db96d56Sopenharmony_ci self.print_topics(self.misc_header, sorted(topics),15,80) 3367db96d56Sopenharmony_ci self.print_topics(self.undoc_header, cmds_undoc, 15,80) 3377db96d56Sopenharmony_ci 3387db96d56Sopenharmony_ci def print_topics(self, header, cmds, cmdlen, maxcol): 3397db96d56Sopenharmony_ci if cmds: 3407db96d56Sopenharmony_ci self.stdout.write("%s\n"%str(header)) 3417db96d56Sopenharmony_ci if self.ruler: 3427db96d56Sopenharmony_ci self.stdout.write("%s\n"%str(self.ruler * len(header))) 3437db96d56Sopenharmony_ci self.columnize(cmds, maxcol-1) 3447db96d56Sopenharmony_ci self.stdout.write("\n") 3457db96d56Sopenharmony_ci 3467db96d56Sopenharmony_ci def columnize(self, list, displaywidth=80): 3477db96d56Sopenharmony_ci """Display a list of strings as a compact set of columns. 3487db96d56Sopenharmony_ci 3497db96d56Sopenharmony_ci Each column is only as wide as necessary. 3507db96d56Sopenharmony_ci Columns are separated by two spaces (one was not legible enough). 3517db96d56Sopenharmony_ci """ 3527db96d56Sopenharmony_ci if not list: 3537db96d56Sopenharmony_ci self.stdout.write("<empty>\n") 3547db96d56Sopenharmony_ci return 3557db96d56Sopenharmony_ci 3567db96d56Sopenharmony_ci nonstrings = [i for i in range(len(list)) 3577db96d56Sopenharmony_ci if not isinstance(list[i], str)] 3587db96d56Sopenharmony_ci if nonstrings: 3597db96d56Sopenharmony_ci raise TypeError("list[i] not a string for i in %s" 3607db96d56Sopenharmony_ci % ", ".join(map(str, nonstrings))) 3617db96d56Sopenharmony_ci size = len(list) 3627db96d56Sopenharmony_ci if size == 1: 3637db96d56Sopenharmony_ci self.stdout.write('%s\n'%str(list[0])) 3647db96d56Sopenharmony_ci return 3657db96d56Sopenharmony_ci # Try every row count from 1 upwards 3667db96d56Sopenharmony_ci for nrows in range(1, len(list)): 3677db96d56Sopenharmony_ci ncols = (size+nrows-1) // nrows 3687db96d56Sopenharmony_ci colwidths = [] 3697db96d56Sopenharmony_ci totwidth = -2 3707db96d56Sopenharmony_ci for col in range(ncols): 3717db96d56Sopenharmony_ci colwidth = 0 3727db96d56Sopenharmony_ci for row in range(nrows): 3737db96d56Sopenharmony_ci i = row + nrows*col 3747db96d56Sopenharmony_ci if i >= size: 3757db96d56Sopenharmony_ci break 3767db96d56Sopenharmony_ci x = list[i] 3777db96d56Sopenharmony_ci colwidth = max(colwidth, len(x)) 3787db96d56Sopenharmony_ci colwidths.append(colwidth) 3797db96d56Sopenharmony_ci totwidth += colwidth + 2 3807db96d56Sopenharmony_ci if totwidth > displaywidth: 3817db96d56Sopenharmony_ci break 3827db96d56Sopenharmony_ci if totwidth <= displaywidth: 3837db96d56Sopenharmony_ci break 3847db96d56Sopenharmony_ci else: 3857db96d56Sopenharmony_ci nrows = len(list) 3867db96d56Sopenharmony_ci ncols = 1 3877db96d56Sopenharmony_ci colwidths = [0] 3887db96d56Sopenharmony_ci for row in range(nrows): 3897db96d56Sopenharmony_ci texts = [] 3907db96d56Sopenharmony_ci for col in range(ncols): 3917db96d56Sopenharmony_ci i = row + nrows*col 3927db96d56Sopenharmony_ci if i >= size: 3937db96d56Sopenharmony_ci x = "" 3947db96d56Sopenharmony_ci else: 3957db96d56Sopenharmony_ci x = list[i] 3967db96d56Sopenharmony_ci texts.append(x) 3977db96d56Sopenharmony_ci while texts and not texts[-1]: 3987db96d56Sopenharmony_ci del texts[-1] 3997db96d56Sopenharmony_ci for col in range(len(texts)): 4007db96d56Sopenharmony_ci texts[col] = texts[col].ljust(colwidths[col]) 4017db96d56Sopenharmony_ci self.stdout.write("%s\n"%str(" ".join(texts))) 402