text: """optik.option_parser
  
  Provides the OptionParser and Values classes.
  """
  
  __revision__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Optik/option_parser.py 0.97.D001 2007/05/17 11:35:19 knight"
  
  # Original Optik revision this is based on:
  __Optik_revision__ = "option_parser.py,v 1.38.2.1 2002/07/23 01:51:14 gward Exp"
  
  # Copyright (c) 2001 Gregory P. Ward.  All rights reserved.
  # See the README.txt distributed with Optik for licensing terms.
  
  # created 2001/10/17, GPW (from optik.py)
  
  import sys, os
  import string
  import types
  from SCons.Optik.option import Option, NO_DEFAULT
  from SCons.Optik.errors import OptionConflictError, OptionValueError, BadOptionError
  
  def get_prog_name ():
      return os.path.basename(sys.argv[0])
  
  
  SUPPRESS_HELP = "SUPPRESS"+"HELP"
  SUPPRESS_USAGE = "SUPPRESS"+"USAGE"
  
  class Values:
  
      def __init__ (self, defaults=None):
          if defaults:
              for (attr, val) in defaults.items():
                  setattr(self, attr, val)
  
  
      def _update_careful (self, dict):
          """
          Update the option values from an arbitrary dictionary, but only
          use keys from dict that already have a corresponding attribute
          in self.  Any keys in dict without a corresponding attribute
          are silently ignored.
          """
          for attr in dir(self):
              if dict.has_key(attr):
                  dval = dict[attr]
                  if dval is not None:
                      setattr(self, attr, dval)
  
      def _update_loose (self, dict):
          """
          Update the option values from an arbitrary dictionary,
          using all keys from the dictionary regardless of whether
          they have a corresponding attribute in self or not.
          """
          self.__dict__.update(dict)
  
      def _update (self, dict, mode):
          if mode == "careful":
              self._update_careful(dict)
          elif mode == "loose":
              self._update_loose(dict)
          else:
              raise ValueError, "invalid update mode: %s" % (repr(mode),)
  
      def read_module (self, modname, mode="careful"):
          __import__(modname)
          mod = sys.modules[modname]
          self._update(vars(mod), mode)
  
      def read_file (self, filename, mode="careful"):
          vars = {}
          execfile(filename, vars)
          self._update(vars, mode)
  
      def ensure_value (self, attr, value):
          if not hasattr(self, attr) or getattr(self, attr) is None:
              setattr(self, attr, value)
          return getattr(self, attr)
  
  
  class OptionParser:
      """
      Class attributes:
        standard_option_list : [Option]
          list of standard options that will be accepted by all instances
          of this parser class (intended to be overridden by subclasses).
  
      Instance attributes:
        usage : string
          a usage string for your program.  Before it is displayed
          to the user, "%prog" will be expanded to the name of
          your program (os.path.basename(sys.argv[0])).
        option_list : [Option]
          the list of all options accepted on the command-line of
          this program
        _short_opt : { string : Option }
          dictionary mapping short option strings, eg. "-f" or "-X",
          to the Option instances that implement them.  If an Option
          has multiple short option strings, it will appears in this
          dictionary multiple times.
        _long_opt : { string : Option }
          dictionary mapping long option strings, eg. "--file" or
          "--exclude", to the Option instances that implement them.
          Again, a given Option can occur multiple times in this
          dictionary.
        defaults : { string : any }
          dictionary mapping option destination names to default
          values for each destination.
  
        allow_interspersed_args : boolean = true
          if true, positional arguments may be interspersed with options.
          Assuming -a and -b each take a single argument, the command-line
            -ablah foo bar -bboo baz
          will be interpreted the same as
            -ablah -bboo -- foo bar baz
          If this flag were false, that command line would be interpreted as
            -ablah -- foo bar -bboo baz
          -- ie. we stop processing options as soon as we see the first
          non-option argument.  (This is the tradition followed by
          Python's getopt module, Perl's Getopt::Std, and other argument-
          parsing libraries, but it is generally annoying to users.)
  
        rargs : [string]
          the argument list currently being parsed.  Only set when
          parse_args() is active, and continually trimmed down as
          we consume arguments.  Mainly there for the benefit of
          callback options.
        largs : [string]
          the list of leftover arguments that we have skipped while
          parsing options.  If allow_interspersed_args is false, this
          list is always empty.
        values : Values
          the set of option values currently being accumulated.  Only
          set when parse_args() is active.  Also mainly for callbacks.
  
      Because of the 'rargs', 'largs', and 'values' attributes,
      OptionParser is not thread-safe.  If, for some perverse reason, you
      need to parse command-line arguments simultaneously in different
      threads, use different OptionParser instances.
      
      """ 
  
      standard_option_list = []
  
  
      def __init__ (self,
                    usage=None,
                    option_list=None,
                    option_class=Option,
                    version=None,
                    conflict_handler="error"):
          self.set_usage(usage)
          self.option_class = option_class
          self.version = version
          self.set_conflict_handler(conflict_handler)
          self.allow_interspersed_args = 1
  
          # Create the various lists and dicts that constitute the
          # "option list".  See class docstring for details about
          # each attribute.
          self._create_option_list()
  
          # Populate the option list; initial sources are the
          # standard_option_list class attribute, the 'option_list'
          # argument, and the STD_VERSION_OPTION global (if 'version'
          # supplied).
          self._populate_option_list(option_list)
  
          self._init_parsing_state()
  
      # -- Private methods -----------------------------------------------
      # (used by the constructor)
  
      def _create_option_list (self):
          self.option_list = []
          self._short_opt = {}            # single letter -> Option instance
          self._long_opt = {}             # long option -> Option instance
          self.defaults = {}              # maps option dest -> default value
  
      def _populate_option_list (self, option_list):
          if self.standard_option_list:
              self.add_options(self.standard_option_list)
          if option_list:
              self.add_options(option_list)
          
      def _init_parsing_state (self):
          # These are set in parse_args() for the convenience of callbacks.
          self.rargs = None
          self.largs = None
          self.values = None
  
  
      # -- Simple modifier methods ---------------------------------------
  
      def set_usage (self, usage):
          if usage is None:
              self.usage = "usage: %prog [options]"
          elif usage is SUPPRESS_USAGE:
              self.usage = None
          else:
              self.usage = usage
  
      def enable_interspersed_args (self):
          self.allow_interspersed_args = 1
  
      def disable_interspersed_args (self):
          self.allow_interspersed_args = 0
  
      def set_conflict_handler (self, handler):
          if handler not in ("ignore", "error", "resolve"):
              raise ValueError, "invalid conflict_resolution value %s" % (repr(handler),)
          self.conflict_handler = handler
  
      def set_default (self, dest, value):
          self.defaults[dest] = value
  
      def set_defaults (self, **kwargs):
          self.defaults.update(kwargs)
  
      def get_default_values(self):
          return Values(self.defaults)
  
  
      # -- Option-adding methods -----------------------------------------
  
      def _check_conflict (self, option):
          conflict_opts = []
          for opt in option._short_opts:
              if self._short_opt.has_key(opt):
                  conflict_opts.append((opt, self._short_opt[opt]))
          for opt in option._long_opts:
              if self._long_opt.has_key(opt):
                  conflict_opts.append((opt, self._long_opt[opt]))
  
          if conflict_opts:
              handler = self.conflict_handler
              if handler == "ignore":     # behaviour for Optik 1.0, 1.1
                  pass
              elif handler == "error":    # new in 1.2
                  raise OptionConflictError(
                      "conflicting option string(s): %s"
                      % string.join( map( lambda x: x[0], conflict_opts),", "),
                      option)
              elif handler == "resolve":  # new in 1.2
                  for (opt, c_option) in conflict_opts:
                      if len(opt)>2 and opt[:2]=="--":
                          c_option._long_opts.remove(opt)
                          del self._long_opt[opt]
                      else:
                          c_option._short_opts.remove(opt)
                          del self._short_opt[opt]
                      if not (c_option._short_opts or c_option._long_opts):
                          self.option_list.remove(c_option)
  
  
      def add_option (self, *args, **kwargs):
          """add_option(Option)
             add_option(opt_str, ..., kwarg=val, ...)
          """
          if type(args[0]) is types.StringType:
              option = apply(self.option_class,args, kwargs)
          elif len(args) == 1 and not kwargs:
              option = args[0]
              if not isinstance(option, Option):
                  raise TypeError, "not an Option instance: %s" % (repr(option),)
          else:
              raise TypeError, "invalid arguments"
  
          self._check_conflict(option)
  
          self.option_list.append(option)
          for opt in option._short_opts:
              self._short_opt[opt] = option
          for opt in option._long_opts:
              self._long_opt[opt] = option
  
          if option.dest is not None:     # option has a dest, we need a default
              if option.default is not NO_DEFAULT:
                  self.defaults[option.dest] = option.default
              elif not self.defaults.has_key(option.dest):
                  self.defaults[option.dest] = None
  
      def add_options (self, option_list):
          for option in option_list:
              self.add_option(option)
  
  
      # -- Option query/removal methods ----------------------------------
  
      def get_option (self, opt_str):
          return (self._short_opt.get(opt_str) or
                  self._long_opt.get(opt_str))
  
      def has_option (self, opt_str):
          return (self._short_opt.has_key(opt_str) or
                  self._long_opt.has_key(opt_str))
  
  
      def remove_option (self, opt_str):
          option = self._short_opt.get(opt_str)
          if option is None:
              option = self._long_opt.get(opt_str)
          if option is None:
              raise ValueError("no such option %s" % (repr(opt_str),))
  
          for opt in option._short_opts:
              del self._short_opt[opt]
          for opt in option._long_opts:
              del self._long_opt[opt]
          self.option_list.remove(option)
  
  
      # -- Option-parsing methods ----------------------------------------
  
      def _get_args (self, args):
          if args is None:
              return sys.argv[1:]
          else:
              return args[:]              # don't modify caller's list
  
      def parse_args (self, args=None, values=None):
          """
          parse_args(args : [string] = sys.argv[1:],
                     values : Values = None)
          -> (values : Values, args : [string])
  
          Parse the command-line options found in 'args' (default:
          sys.argv[1:]).  Any errors result in a call to 'error()', which
          by default prints the usage message to stderr and calls
          sys.exit() with an error message.  On success returns a pair
          (values, args) where 'values' is an Values instance (with all
          your option values) and 'args' is the list of arguments left
          over after parsing options.
          """
          rargs = self._get_args(args)
          if values is None:
              values = self.get_default_values()
  
          # Store the halves of the argument list as attributes for the
          # convenience of callbacks:
          #   rargs
          #     the rest of the command-line (the "r" stands for
          #     "remaining" or "right-hand")
          #   largs
          #     the leftover arguments -- ie. what's left after removing
          #     options and their arguments (the "l" stands for "leftover"
          #     or "left-hand")
          self.rargs = rargs
          self.largs = largs = []
          self.values = values
  
          try:
              stop = self._process_args(largs, rargs, values)
          except (BadOptionError, OptionValueError), err:
              self.error(err.msg)
  
          args = largs + rargs
          return self.check_values(values, args)
  
      def check_values (self, values, args):
          """
          check_values(values : Values, args : [string])
          -> (values : Values, args : [string])
  
          Check that the supplied option values and leftover arguments are
          valid.  Returns the option values and leftover arguments
          (possibly adjusted, possibly completely new -- whatever you
          like).  Default implementation just returns the passed-in
          values; subclasses may override as desired.
          """
          return (values, args)
  
      def _process_args (self, largs, rargs, values):
          """_process_args(largs : [string],
                           rargs : [string],
                           values : Values)
  
          Process command-line arguments and populate 'values', consuming
          options and arguments from 'rargs'.  If 'allow_interspersed_args' is
          false, stop at the first non-option argument.  If true, accumulate any
          interspersed non-option arguments in 'largs'.
          """
          while rargs:
              arg = rargs[0]
              # We handle bare "--" explicitly, and bare "-" is handled by the
              # standard arg handler since the short arg case ensures that the
              # len of the opt string is greater than 1.
              if arg == "--":
                  del rargs[0]
                  return
              elif arg[0:2] == "--":
                  # process a single long option (possibly with value(s))
                  self._process_long_opt(rargs, values)
              elif arg[:1] == "-" and len(arg) > 1:
                  # process a cluster of short options (possibly with
                  # value(s) for the last one only)
                  self._process_short_opts(rargs, values)
              elif self.allow_interspersed_args:
                  largs.append(arg)
                  del rargs[0]
              else:
                  return                  # stop now, leave this arg in rargs
  
          # Say this is the original argument list:
          # [arg0, arg1, ..., arg(i-1), arg(i), arg(i+1), ..., arg(N-1)]
          #                            ^
          # (we are about to process arg(i)).
          #
          # Then rargs is [arg(i), ..., arg(N-1)] and largs is a *subset* of
          # [arg0, ..., arg(i-1)] (any options and their arguments will have
          # been removed from largs).
          #
          # The while loop will usually consume 1 or more arguments per pass.
          # If it consumes 1 (eg. arg is an option that takes no arguments),
          # then after _process_arg() is done the situation is:
          #
          #   largs = subset of [arg0, ..., arg(i)]
          #   rargs = [arg(i+1), ..., arg(N-1)]
          #
          # If allow_interspersed_args is false, largs will always be
          # *empty* -- still a subset of [arg0, ..., arg(i-1)], but
          # not a very interesting subset!
          
      def _match_long_opt (self, opt):
          """_match_long_opt(opt : string) -> string
  
          Determine which long option string 'opt' matches, ie. which one
          it is an unambiguous abbrevation for.  Raises BadOptionError if
          'opt' doesn't unambiguously match any long option string.
          """
          return _match_abbrev(opt, self._long_opt)
  
      def _process_long_opt (self, rargs, values):
          arg = rargs.pop(0)
  
          # Value explicitly attached to arg?  Pretend it's the next
          # argument.
          if "=" in arg:
              (opt, next_arg) = string.split(arg,"=", 1)
              rargs.insert(0, next_arg)
              had_explicit_value = 1
          else:
              opt = arg
              had_explicit_value = 0
  
          opt = self._match_long_opt(opt)
          option = self._long_opt[opt]
          if option.takes_value():
              nargs = option.nargs
              if len(rargs) < nargs:
                  if nargs == 1:
                      self.error("%s option requires a value" % opt)
                  else:
                      self.error("%s option requires %d values"
                                 % (opt, nargs))
              elif nargs == 1:
                  value = rargs.pop(0)
              else:
                  value = tuple(rargs[0:nargs])
                  del rargs[0:nargs]
  
          elif had_explicit_value:
              self.error("%s option does not take a value" % opt)
  
          else:
              value = None
  
          option.process(opt, value, values, self)
  
      def _process_short_opts (self, rargs, values):
          arg = rargs.pop(0)
          stop = 0
          i = 1
          for ch in arg[1:]:
              opt = "-" + ch
              option = self._short_opt.get(opt)
              i = i+1                      # we have consumed a character
  
              if not option:
                  self.error("no such option: %s" % opt)
              if option.takes_value():
                  # Any characters left in arg?  Pretend they're the
                  # next arg, and stop consuming characters of arg.
                  if i < len(arg):
                      rargs.insert(0, arg[i:])
                      stop = 1
  
                  nargs = option.nargs
                  if len(rargs) < nargs:
                      if nargs == 1:
                          self.error("%s option requires a value" % opt)
                      else:
                          self.error("%s option requires %s values"
                                     % (opt, nargs))
                  elif nargs == 1:
                      value = rargs.pop(0)
                  else:
                      value = tuple(rargs[0:nargs])
                      del rargs[0:nargs]
  
              else:                       # option doesn't take a value
                  value = None
  
              option.process(opt, value, values, self)
  
              if stop:
                  break
  
  
      # -- Output/error methods ------------------------------------------
  
      def error (self, msg):
          """error(msg : string)
  
          Print a usage message incorporating 'msg' to stderr and exit.
          If you override this in a subclass, it should not return -- it
          should either exit or raise an exception.
          """
          self.print_usage(sys.stderr)
          sys.stderr.write("\nSCons error: %s\n" % msg)
          sys.exit(2)
  
      def print_usage (self, file=None):
          """print_usage(file : file = stdout)
  
          Print the usage message for the current program (self.usage) to
          'file' (default stdout).  Any occurence of the string "%prog" in
          self.usage is replaced with the name of the current program
          (basename of sys.argv[0]).  Does nothing if self.usage is empty
          or not defined.
          """
          if file is None:
              file = sys.stdout
          if self.usage:
              usage = string.replace(self.usage,"%prog", get_prog_name())
              file.write(usage + "\n")
  
      def print_version (self, file=None):
          """print_version(file : file = stdout)
  
          Print the version message for this program (self.version) to
          'file' (default stdout).  As with print_usage(), any occurence
          of "%prog" in self.version is replaced by the current program's
          name.  Does nothing if self.version is empty or undefined.
          """
          if file is None:
              file = sys.stdout
          if self.version:
              version = string.replace(self.version,"%prog", get_prog_name())
              file.write(version+"\n")
  
      def print_help (self, file=None):
          """print_help(file : file = stdout)
  
          Print an extended help message, listing all options and any
          help text provided with them, to 'file' (default stdout).
          """
          # SCons:  don't import wrap_text from distutils, use the
          # copy we've included below, so we can avoid being dependent
          # on having the right version of distutils installed.
          #from distutils.fancy_getopt import wrap_text
          
          if file is None:
              file = sys.stdout
  
          self.print_usage(file)
  
          # The help for each option consists of two parts:
          #   * the opt strings and metavars
          #     eg. ("-x", or "-fFILENAME, --file=FILENAME")
          #   * the user-supplied help string
          #     eg. ("turn on expert mode", "read data from FILENAME")
          #
          # If possible, we write both of these on the same line:
          #   -x      turn on expert mode
          # 
          # But if the opt string list is too long, we put the help
          # string on a second line, indented to the same column it would
          # start in if it fit on the first line.
          #   -fFILENAME, --file=FILENAME
          #           read data from FILENAME
  
          file.write("Options:\n")
          width = 78                      # assume 80 cols for now
  
          option_help = []                # list of (string, string) tuples
          lengths = []
  
          for option in self.option_list:
              takes_value = option.takes_value()
              if takes_value:
                  metavar = option.metavar or string.upper(option.dest)
  
              opts = []               # list of "-a" or "--foo=FILE" strings
              if option.help is SUPPRESS_HELP:
                  continue
  
              if takes_value:
                  for sopt in option._short_opts:
                      opts.append(sopt + ' ' + metavar)
                  for lopt in option._long_opts:
                      opts.append(lopt + "=" + metavar)
              else:
                  for opt in option._short_opts + option._long_opts:
                      opts.append(opt)
  
              opts = string.join(opts,", ")
              option_help.append((opts, option.help))
              lengths.append(len(opts))
  
          max_opts = min(max(lengths), 26)
  
          for (opts, help) in option_help:
              # how much to indent lines 2 .. N of help text
              indent_rest = 2 + max_opts + 2 
              help_width = width - indent_rest
  
              if len(opts) > max_opts:
                  opts = "  " + opts + "\n"
                  indent_first = indent_rest
              else:                       # start help on same line as opts
                  opts = "  %-*s  " % (max_opts, opts)
                  indent_first = 0
  
              file.write(opts)
  
              if help:
                  help_lines = wrap_text(help, help_width)
                  file.write( "%*s%s\n" % (indent_first, "", help_lines[0]))
                  for line in help_lines[1:]:
                      file.write("  %*s%s\n" % (indent_rest, "", line))
              elif opts[-1] != "\n":
                  file.write("\n")
  
  # class OptionParser
  
  
  def _match_abbrev (s, wordmap):
      """_match_abbrev(s : string, wordmap : {string : Option}) -> string
  
      Return the string key in 'wordmap' for which 's' is an unambiguous
      abbreviation.  If 's' is found to be ambiguous or doesn't match any of
      'words', raise BadOptionError.
      """
      # Is there an exact match?
      if wordmap.has_key(s):
          return s
      else:
          # Isolate all words with s as a prefix.
          possibilities = []
          ls = len(s)
          for word in wordmap.keys():
              if len(word)>=ls and word[:ls]==s:
                  possibilities.append(word)
          # No exact match, so there had better be just one possibility.
          if len(possibilities) == 1:
              return possibilities[0]
          elif not possibilities:
              raise BadOptionError("no such option: %s" % s)
          else:
              # More than one possible completion: ambiguous prefix.
              raise BadOptionError("ambiguous option: %s (%s?)"
                                   % (s, string.join(possibilities,", ")))
  
  # SCons:  Include a snarfed copy of wrap_text(), so we're not dependent
  # on the right version of distutils being installed.
  import re
  
  WS_TRANS = string.maketrans(string.whitespace, ' ' * len(string.whitespace))
  
  def wrap_text (text, width):
      """wrap_text(text : string, width : int) -> [string]
  
      Split 'text' into multiple lines of no more than 'width' characters
      each, and return the list of strings that results.
      """
  
      if text is None:
          return []
      if len(text) <= width:
          return [text]
  
      text = string.expandtabs(text)
      text = string.translate(text, WS_TRANS)
      chunks = re.split(r'( +|-+)', text)
      chunks = filter(None, chunks)      # ' - ' results in empty strings
      lines = []
  
      while chunks:
  
          cur_line = []                   # list of chunks (to-be-joined)
          cur_len = 0                     # length of current line
  
          while chunks:
              l = len(chunks[0])
              if cur_len + l <= width:    # can squeeze (at least) this chunk in
                  cur_line.append(chunks[0])
                  del chunks[0]
                  cur_len = cur_len + l
              else:                       # this line is full
                  # drop last chunk if all space
                  if cur_line and cur_line[-1][0] == ' ':
                      del cur_line[-1]
                  break
  
          if chunks:                      # any chunks left to process?
  
              # if the current line is still empty, then we had a single
              # chunk that's too big too fit on a line -- so we break
              # down and break it up at the line width
              if cur_len == 0:
                  cur_line.append(chunks[0][0:width])
                  chunks[0] = chunks[0][width:]
  
              # all-whitespace chunks at the end of a line can be discarded
              # (and we know from the re.split above that if a chunk has
              # *any* whitespace, it is *all* whitespace)
              if chunks[0][0] == ' ':
                  del chunks[0]
  
          # and store this line in the list-of-all-lines -- as a single
          # string, of course!
          lines.append(string.join(cur_line, ''))
  
      # while chunks
  
      return lines
  
  # wrap_text ()
  