Introspect sub-command handler signature to determine how to
        dispatch the command. The raw handler provided by the base
        'RawCmdln' class is still supported:

            def do_foo(self, argv):
                # 'argv' is the vector of command line args, argv[0] is
                # the command name itself (i.e. "foo" or an alias)
                pass

        In addition, if the handler has more than 2 arguments option
        processing is automatically done (using optparse):

            @cmdln.option('-v', '--verbose', action='store_true')
            def do_bar(self, subcmd, opts, *args):
                # subcmd = <"bar" or an alias>
                # opts = <an optparse.Values instance>
                if opts.verbose:
                    print "lots of debugging output..."
                # args = <tuple of arguments>
                for arg in args:
                    bar(arg)

        TODO: explain that "*args" can be other signatures as well.

        The `cmdln.option` decorator corresponds to an `add_option()`
        method call on an `optparse.OptionParser` instance.

        You can declare a specific number of arguments:

            @cmdln.option('-v', '--verbose', action='store_true')
            def do_bar2(self, subcmd, opts, bar_one, bar_two):
                #...

        and an appropriate error message will be raised/printed if the
        command is called with a different number of args.

def _dispatch_cmd(self, handler, argv):
        """Introspect sub-command handler signature to determine how to
        dispatch the command. The raw handler provided by the base
        'RawCmdln' class is still supported:

            def do_foo(self, argv):
                # 'argv' is the vector of command line args, argv[0] is
                # the command name itself (i.e. "foo" or an alias)
                pass

        In addition, if the handler has more than 2 arguments option
        processing is automatically done (using optparse):

            @cmdln.option('-v', '--verbose', action='store_true')
            def do_bar(self, subcmd, opts, *args):
                # subcmd = <"bar" or an alias>
                # opts = <an optparse.Values instance>
                if opts.verbose:
                    print "lots of debugging output..."
                # args = <tuple of arguments>
                for arg in args:
                    bar(arg)

        TODO: explain that "*args" can be other signatures as well.

        The `cmdln.option` decorator corresponds to an `add_option()`
        method call on an `optparse.OptionParser` instance.

        You can declare a specific number of arguments:

            @cmdln.option('-v', '--verbose', action='store_true')
            def do_bar2(self, subcmd, opts, bar_one, bar_two):
                #...

        and an appropriate error message will be raised/printed if the
        command is called with a different number of args.
        """
        co_argcount = handler.__func__.__code__.co_argcount
        if co_argcount == 2:   # handler ::= do_foo(self, argv)
            return handler(argv)
        elif co_argcount >= 3: # handler ::= do_foo(self, subcmd, opts, ...)
            try:
                optparser = handler.optparser
            except AttributeError:
                optparser = handler.__func__.optparser = SubCmdOptionParser()
            assert isinstance(optparser, SubCmdOptionParser)

            # apply subcommand options' defaults from config files, if any.
            subcmd = handler.__name__.split('do_', 1)[1]
            optparser.set_defaults(**self.get_option_defaults(subcmd))
            
            optparser.set_cmdln_info(self, argv[0])
            try:
                opts, args = optparser.parse_args(argv[1:])
            except StopOptionProcessing:
                #TODO: this doesn't really fly for a replacement of
                #      optparse.py behaviour, does it?
                return 0 # Normal command termination

            try:
                return handler(argv[0], opts, *args)
            except TypeError:
                _, ex, _ = sys.exc_info()
                # Some TypeError's are user errors:
                #   do_foo() takes at least 4 arguments (3 given)
                #   do_foo() takes at most 5 arguments (6 given)
                #   do_foo() takes exactly 5 arguments (6 given)
                #   do_foo() takes exactly 5 positional arguments (6 given)
                # Raise CmdlnUserError for these with a suitably
                # massaged error message.
                tb = sys.exc_info()[2] # the traceback object
                if tb.tb_next is not None:
                    # If the traceback is more than one level deep, then the
                    # TypeError do *not* happen on the "handler(...)" call
                    # above. In that we don't want to handle it specially
                    # here: it would falsely mask deeper code errors.
                    raise
                msg = ex.args[0]
                match = _INCORRECT_NUM_ARGS_RE.search(msg)
                if match:
                    msg = list(match.groups())
                    msg[1] = int(msg[1]) - 3
                    if msg[1] == 1:
                        msg[2] = msg[2].replace("arguments", "argument")
                    msg[3] = int(msg[3]) - 3
                    msg = ''.join(map(str, msg))
                    raise CmdlnUserError(msg)
                else:
                    raise
        else:
            raise CmdlnError("incorrect argcount for %s(): takes %d, must "
                             "take 2 for 'argv' signature or 3+ for 'opts' "
                             "signature" % (handler.__name__, co_argcount))