1ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh"""A generic class to build line-oriented command interpreters.
2ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
3ffab958fd8d42ed7227d83007350e61555a1fa36Andrew HsiehInterpreters constructed with this class obey the following conventions:
4ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
5ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh1. End of file on input is processed as the command 'EOF'.
6ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh2. A command is parsed out of each line by collecting the prefix composed
7ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh   of characters in the identchars member.
8ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh3. A command `foo' is dispatched to a method 'do_foo()'; the do_ method
9ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh   is passed a single argument consisting of the remainder of the line.
10ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh4. Typing an empty line repeats the last command.  (Actually, it calls the
11ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh   method `emptyline', which may be overridden in a subclass.)
12ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh5. There is a predefined `help' method.  Given an argument `topic', it
13ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh   calls the command `help_topic'.  With no arguments, it lists all topics
14ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh   with defined help_ functions, broken into up to three topics; documented
15ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh   commands, miscellaneous help topics, and undocumented commands.
16ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh6. The command '?' is a synonym for `help'.  The command '!' is a synonym
17ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh   for `shell', if a do_shell method exists.
18ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh7. If completion is enabled, completing commands will be done automatically,
19ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh   and completing of commands args is done by calling complete_foo() with
20ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh   arguments text, line, begidx, endidx.  text is string we are matching
21ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh   against, all returned matches must begin with it.  line is the current
22ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh   input line (lstripped), begidx and endidx are the beginning and end
23ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh   indexes of the text being matched, which could be used to provide
24ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh   different completion depending upon which position the argument is in.
25ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
26ffab958fd8d42ed7227d83007350e61555a1fa36Andrew HsiehThe `default' method may be overridden to intercept commands for which there
27ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsiehis no do_ method.
28ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
29ffab958fd8d42ed7227d83007350e61555a1fa36Andrew HsiehThe `completedefault' method may be overridden to intercept completions for
30ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsiehcommands that have no complete_ method.
31ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
32ffab958fd8d42ed7227d83007350e61555a1fa36Andrew HsiehThe data member `self.ruler' sets the character used to draw separator lines
33ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsiehin the help messages.  If empty, no ruler line is drawn.  It defaults to "=".
34ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
35ffab958fd8d42ed7227d83007350e61555a1fa36Andrew HsiehIf the value of `self.intro' is nonempty when the cmdloop method is called,
36ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsiehit is printed out on interpreter startup.  This value may be overridden
37ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsiehvia an optional argument to the cmdloop() method.
38ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
39ffab958fd8d42ed7227d83007350e61555a1fa36Andrew HsiehThe data members `self.doc_header', `self.misc_header', and
40ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh`self.undoc_header' set the headers used for the help function's
41ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsiehlistings of documented functions, miscellaneous topics, and undocumented
42ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsiehfunctions respectively.
43ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
44ffab958fd8d42ed7227d83007350e61555a1fa36Andrew HsiehThese interpreters use raw_input; thus, if the readline module is loaded,
45ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsiehthey automatically support Emacs-like command history and editing features.
46ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh"""
47ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
48ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsiehimport string
49ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
50ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh__all__ = ["Cmd"]
51ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
52ffab958fd8d42ed7227d83007350e61555a1fa36Andrew HsiehPROMPT = '(Cmd) '
53ffab958fd8d42ed7227d83007350e61555a1fa36Andrew HsiehIDENTCHARS = string.ascii_letters + string.digits + '_'
54ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
55ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsiehclass Cmd:
56ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    """A simple framework for writing line-oriented command interpreters.
57ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
58ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    These are often useful for test harnesses, administrative tools, and
59ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    prototypes that will later be wrapped in a more sophisticated interface.
60ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
61ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    A Cmd instance or subclass instance is a line-oriented interpreter
62ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    framework.  There is no good reason to instantiate Cmd itself; rather,
63ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    it's useful as a superclass of an interpreter class you define yourself
64ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    in order to inherit Cmd's methods and encapsulate action methods.
65ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
66ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    """
67ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    prompt = PROMPT
68ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    identchars = IDENTCHARS
69ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    ruler = '='
70ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    lastcmd = ''
71ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    intro = None
72ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    doc_leader = ""
73ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    doc_header = "Documented commands (type help <topic>):"
74ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    misc_header = "Miscellaneous help topics:"
75ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    undoc_header = "Undocumented commands:"
76ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    nohelp = "*** No help on %s"
77ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    use_rawinput = 1
78ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
79ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def __init__(self, completekey='tab', stdin=None, stdout=None):
80ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        """Instantiate a line-oriented interpreter framework.
81ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
82ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        The optional argument 'completekey' is the readline name of a
83ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        completion key; it defaults to the Tab key. If completekey is
84ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        not None and the readline module is available, command completion
85ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        is done automatically. The optional arguments stdin and stdout
86ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        specify alternate input and output file objects; if not specified,
87ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        sys.stdin and sys.stdout are used.
88ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
89ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        """
90ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        import sys
91ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        if stdin is not None:
92ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.stdin = stdin
93ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        else:
94ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.stdin = sys.stdin
95ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        if stdout is not None:
96ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.stdout = stdout
97ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        else:
98ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.stdout = sys.stdout
99ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.cmdqueue = []
100ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.completekey = completekey
101ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
102ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def cmdloop(self, intro=None):
103ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        """Repeatedly issue a prompt, accept input, parse an initial prefix
104ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        off the received input, and dispatch to action methods, passing them
105ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        the remainder of the line as argument.
106ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
107ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        """
108ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
109ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.preloop()
110ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        if self.use_rawinput and self.completekey:
111ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            try:
112ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                import readline
113ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                self.old_completer = readline.get_completer()
114ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                readline.set_completer(self.complete)
115ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                readline.parse_and_bind(self.completekey+": complete")
116ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            except ImportError:
117ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                pass
118ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        try:
119ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            if intro is not None:
120ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                self.intro = intro
121ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            if self.intro:
122ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                self.stdout.write(str(self.intro)+"\n")
123ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            stop = None
124ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            while not stop:
125ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                if self.cmdqueue:
126ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                    line = self.cmdqueue.pop(0)
127ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                else:
128ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                    if self.use_rawinput:
129ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                        try:
130ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                            line = raw_input(self.prompt)
131ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                        except EOFError:
132ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                            line = 'EOF'
133ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                    else:
134ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                        self.stdout.write(self.prompt)
135ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                        self.stdout.flush()
136ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                        line = self.stdin.readline()
137ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                        if not len(line):
138ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                            line = 'EOF'
139ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                        else:
140ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                            line = line.rstrip('\r\n')
141ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                line = self.precmd(line)
142ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                stop = self.onecmd(line)
143ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                stop = self.postcmd(stop, line)
144ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.postloop()
145ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        finally:
146ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            if self.use_rawinput and self.completekey:
147ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                try:
148ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                    import readline
149ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                    readline.set_completer(self.old_completer)
150ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                except ImportError:
151ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                    pass
152ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
153ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
154ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def precmd(self, line):
155ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        """Hook method executed just before the command line is
156ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        interpreted, but after the input prompt is generated and issued.
157ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
158ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        """
159ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        return line
160ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
161ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def postcmd(self, stop, line):
162ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        """Hook method executed just after a command dispatch is finished."""
163ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        return stop
164ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
165ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def preloop(self):
166ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        """Hook method executed once when the cmdloop() method is called."""
167ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        pass
168ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
169ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def postloop(self):
170ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        """Hook method executed once when the cmdloop() method is about to
171ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        return.
172ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
173ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        """
174ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        pass
175ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
176ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def parseline(self, line):
177ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        """Parse the line into a command name and a string containing
178ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        the arguments.  Returns a tuple containing (command, args, line).
179ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        'command' and 'args' may be None if the line couldn't be parsed.
180ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        """
181ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        line = line.strip()
182ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        if not line:
183ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            return None, None, line
184ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        elif line[0] == '?':
185ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            line = 'help ' + line[1:]
186ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        elif line[0] == '!':
187ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            if hasattr(self, 'do_shell'):
188ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                line = 'shell ' + line[1:]
189ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            else:
190ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                return None, None, line
191ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        i, n = 0, len(line)
192ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        while i < n and line[i] in self.identchars: i = i+1
193ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        cmd, arg = line[:i], line[i:].strip()
194ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        return cmd, arg, line
195ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
196ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def onecmd(self, line):
197ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        """Interpret the argument as though it had been typed in response
198ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        to the prompt.
199ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
200ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        This may be overridden, but should not normally need to be;
201ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        see the precmd() and postcmd() methods for useful execution hooks.
202ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        The return value is a flag indicating whether interpretation of
203ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        commands by the interpreter should stop.
204ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
205ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        """
206ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        cmd, arg, line = self.parseline(line)
207ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        if not line:
208ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            return self.emptyline()
209ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        if cmd is None:
210ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            return self.default(line)
211ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.lastcmd = line
212ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        if line == 'EOF' :
213ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.lastcmd = ''
214ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        if cmd == '':
215ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            return self.default(line)
216ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        else:
217ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            try:
218ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                func = getattr(self, 'do_' + cmd)
219ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            except AttributeError:
220ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                return self.default(line)
221ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            return func(arg)
222ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
223ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def emptyline(self):
224ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        """Called when an empty line is entered in response to the prompt.
225ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
226ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        If this method is not overridden, it repeats the last nonempty
227ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        command entered.
228ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
229ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        """
230ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        if self.lastcmd:
231ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            return self.onecmd(self.lastcmd)
232ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
233ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def default(self, line):
234ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        """Called on an input line when the command prefix is not recognized.
235ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
236ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        If this method is not overridden, it prints an error message and
237ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        returns.
238ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
239ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        """
240ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.stdout.write('*** Unknown syntax: %s\n'%line)
241ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
242ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def completedefault(self, *ignored):
243ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        """Method called to complete an input line when no command-specific
244ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        complete_*() method is available.
245ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
246ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        By default, it returns an empty list.
247ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
248ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        """
249ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        return []
250ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
251ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def completenames(self, text, *ignored):
252ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        dotext = 'do_'+text
253ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        return [a[3:] for a in self.get_names() if a.startswith(dotext)]
254ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
255ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def complete(self, text, state):
256ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        """Return the next possible completion for 'text'.
257ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
258ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        If a command has not been entered, then complete against command list.
259ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        Otherwise try to call complete_<command> to get list of completions.
260ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        """
261ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        if state == 0:
262ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            import readline
263ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            origline = readline.get_line_buffer()
264ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            line = origline.lstrip()
265ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            stripped = len(origline) - len(line)
266ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            begidx = readline.get_begidx() - stripped
267ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            endidx = readline.get_endidx() - stripped
268ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            if begidx>0:
269ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                cmd, args, foo = self.parseline(line)
270ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                if cmd == '':
271ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                    compfunc = self.completedefault
272ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                else:
273ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                    try:
274ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                        compfunc = getattr(self, 'complete_' + cmd)
275ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                    except AttributeError:
276ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                        compfunc = self.completedefault
277ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            else:
278ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                compfunc = self.completenames
279ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.completion_matches = compfunc(text, line, begidx, endidx)
280ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        try:
281ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            return self.completion_matches[state]
282ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        except IndexError:
283ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            return None
284ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
285ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def get_names(self):
286ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # This method used to pull in base class attributes
287ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # at a time dir() didn't do it yet.
288ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        return dir(self.__class__)
289ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
290ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def complete_help(self, *args):
291ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        commands = set(self.completenames(*args))
292ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        topics = set(a[5:] for a in self.get_names()
293ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                     if a.startswith('help_' + args[0]))
294ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        return list(commands | topics)
295ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
296ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def do_help(self, arg):
297ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        'List available commands with "help" or detailed help with "help cmd".'
298ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        if arg:
299ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            # XXX check arg syntax
300ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            try:
301ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                func = getattr(self, 'help_' + arg)
302ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            except AttributeError:
303ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                try:
304ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                    doc=getattr(self, 'do_' + arg).__doc__
305ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                    if doc:
306ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                        self.stdout.write("%s\n"%str(doc))
307ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                        return
308ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                except AttributeError:
309ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                    pass
310ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                self.stdout.write("%s\n"%str(self.nohelp % (arg,)))
311ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                return
312ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            func()
313ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        else:
314ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            names = self.get_names()
315ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            cmds_doc = []
316ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            cmds_undoc = []
317ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            help = {}
318ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            for name in names:
319ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                if name[:5] == 'help_':
320ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                    help[name[5:]]=1
321ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            names.sort()
322ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            # There can be duplicates if routines overridden
323ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            prevname = ''
324ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            for name in names:
325ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                if name[:3] == 'do_':
326ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                    if name == prevname:
327ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                        continue
328ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                    prevname = name
329ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                    cmd=name[3:]
330ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                    if cmd in help:
331ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                        cmds_doc.append(cmd)
332ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                        del help[cmd]
333ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                    elif getattr(self, name).__doc__:
334ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                        cmds_doc.append(cmd)
335ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                    else:
336ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                        cmds_undoc.append(cmd)
337ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.stdout.write("%s\n"%str(self.doc_leader))
338ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.print_topics(self.doc_header,   cmds_doc,   15,80)
339ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.print_topics(self.misc_header,  help.keys(),15,80)
340ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.print_topics(self.undoc_header, cmds_undoc, 15,80)
341ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
342ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def print_topics(self, header, cmds, cmdlen, maxcol):
343ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        if cmds:
344ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.stdout.write("%s\n"%str(header))
345ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            if self.ruler:
346ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                self.stdout.write("%s\n"%str(self.ruler * len(header)))
347ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.columnize(cmds, maxcol-1)
348ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.stdout.write("\n")
349ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
350ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def columnize(self, list, displaywidth=80):
351ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        """Display a list of strings as a compact set of columns.
352ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
353ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        Each column is only as wide as necessary.
354ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        Columns are separated by two spaces (one was not legible enough).
355ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        """
356ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        if not list:
357ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.stdout.write("<empty>\n")
358ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            return
359ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        nonstrings = [i for i in range(len(list))
360ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                        if not isinstance(list[i], str)]
361ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        if nonstrings:
362ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            raise TypeError, ("list[i] not a string for i in %s" %
363ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                              ", ".join(map(str, nonstrings)))
364ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        size = len(list)
365ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        if size == 1:
366ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.stdout.write('%s\n'%str(list[0]))
367ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            return
368ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # Try every row count from 1 upwards
369ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        for nrows in range(1, len(list)):
370ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            ncols = (size+nrows-1) // nrows
371ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            colwidths = []
372ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            totwidth = -2
373ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            for col in range(ncols):
374ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                colwidth = 0
375ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                for row in range(nrows):
376ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                    i = row + nrows*col
377ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                    if i >= size:
378ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                        break
379ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                    x = list[i]
380ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                    colwidth = max(colwidth, len(x))
381ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                colwidths.append(colwidth)
382ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                totwidth += colwidth + 2
383ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                if totwidth > displaywidth:
384ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                    break
385ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            if totwidth <= displaywidth:
386ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                break
387ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        else:
388ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            nrows = len(list)
389ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            ncols = 1
390ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            colwidths = [0]
391ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        for row in range(nrows):
392ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            texts = []
393ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            for col in range(ncols):
394ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                i = row + nrows*col
395ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                if i >= size:
396ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                    x = ""
397ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                else:
398ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                    x = list[i]
399ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                texts.append(x)
400ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            while texts and not texts[-1]:
401ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                del texts[-1]
402ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            for col in range(len(texts)):
403ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                texts[col] = texts[col].ljust(colwidths[col])
404ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.stdout.write("%s\n"%str("  ".join(texts)))
405