docs: def parse_args(args=None):
      """Parse command line arguments."""
      # The argparse module provides a nice abstraction for argument parsing.
      # It automatically builds up the help text, too.
      parser = argparse.ArgumentParser(
              prog=__package__,
              description='Make substitutions in text files.',
          )
      parser.add_argument('-V', '--version',
                          action='version',
                          version="%%(prog)s %s" % (__version__,),
                          )
  
      group = parser.add_argument_group("Engine")
      group.add_argument('-e', '--engine',
                         dest='engine',
                         default='string.Template',
                         help="templating engine",
                         metavar="ENGINE",
                         )
      group.add_argument('-t', '--tolerant',
                         action='store_true',
                         dest='tolerant',
                         help="don't fail on missing names",
                         )
  
      group = parser.add_argument_group("Output")
      group.add_argument('-s', '--stdout',
                         action='append_const',
                         dest='outfiles',
                         const=sys.stdout,
                         help="use standard output",
                         )
      group.add_argument('-o', '--outfile',
                         action='append',
                         dest='outfiles',
                         help="output file",
                         metavar="FILE",
                         )
      group.add_argument('--vary',
                         action='store_true',
                         dest='vary',
                         help="vary output file name according to template",
                         )
      group.add_argument('-r', '--read-old',
                         action='store_true',
                         dest='read_old',
                         help="read preexisting output files and"
                              "hand the respective content to the template",
                         )
      group.add_argument('-d', '--delete-empty',
                         action='store_true',
                         dest='delete_empty',
                         help="delete file if output is empty",
                         )
  
      group = parser.add_argument_group("Input")
      group.add_argument('--stdin',
                         action='append_const',
                         dest='infiles',
                         const=sys.stdin,
                         help="use standard input",
                         )
      group.add_argument('-i', '--infile',
                         action='append',
                         dest='infiles',
                         help="any number of input files",
                         metavar="FILE",
                         )
      group.add_argument('-c', '--concatenate',
                         action='store_true',
                         dest='concatenate',
                         help="concatenate multiple input files into one output",
                         )
  
      group = parser.add_argument_group("Name-value pairs")
      group.add_argument('-a', '--arg',
                         action='append',
                         dest='args',
                         help="any number of name-value pairs",
                         metavar="NAME=VALUE",
                         )
      group.add_argument('-p', '--pyarg',
                         action='append',
                         dest='args',
                         type=_PyArg,
                         help="evaluate a python expression",
                         metavar="NAME=EXPRESSION",
                         )
      group.add_argument('-n', '--next',
                         action='append_const',
                         dest='args',
                         const='--',
                         help="begin next argument group",
                         )
  
      parser.add_argument(
                          dest='remainder',
                          nargs=argparse.REMAINDER,
                          help="possible input files and name-value pair groups "
                               "if not already specified through options",
                          )
  
      args = parser.parse_args(args)
  
      if args.engine == 'help':
          dump_engines()
          parser.exit(0)
  
      if args.engine not in engines.engines:
          parser.error("Engine '%s' is not available." % (args.engine,))
  
      if args.vary:
          if len(args.outfiles) != 1:
              parser.error("need exactly one output file template")
          if is_filelike(args.outfiles[0]):
              parser.error("vary requires an output file template")
      elif not args.outfiles:
          args.outfiles = [sys.stdout]
  
      if not args.infiles:
          if args.args:
              infiles = args.remainder
              args.remainder = []
              try:
                  infiles.remove('--')
              except ValueError:
                  pass
          else:
              first = 1 if args.remainder and args.remainder[0] == '--' else 0
              last = (len(args.remainder)
                      if args.vary or args.concatenate
                      else first + 1)
              for split, infile in enumerate(args.remainder[first:last], first):
                  if infile == '--' or '=' in infile:
                      break
              else:
                  split = last
  
              infiles = args.remainder[first:split]
              args.remainder = args.remainder[split:]
  
          args.infiles = [path if path != '-' else sys.stdin
                          for path in infiles] if infiles else [sys.stdin]
  
      if args.args:
          flat_args = args.args
      else:
          flat_args = args.remainder
          args.remainder = []
          if flat_args and flat_args[0] == '--':
              flat_args = flat_args[1:]
  
      args.args = []
      mapping = {}
      for arg in flat_args:
          if isinstance(arg, _PyArg):
              name_value = arg.split('=', 1)
              mapping[name_value[0]] = eval(name_value[1], {}, mapping)
          elif arg == '--':
              args.args.append(mapping)
              mapping = {}
          else:
              name_value = arg.split('=', 1)
              mapping[name_value[0]] = (name_value[1]
                                        if len(name_value) > 1
                                        else None)
      args.args.append(mapping)
  
      if args.remainder:
          parser.error("extraneous arguments left over")
      else:
          del args.remainder
  
      return args