Parse command line arguments and return a dictionary of options
    for ttfautohint.ttfautohint function.

    `args` can be either None, a list of strings, or a single string,
    that is split into individual options with `shlex.split`.

    When `args` is None, the console's default sys.argv are used, and any
    SystemExit exceptions raised by argparse are propagated.

    If args is a string list or a string, it is assumed that the function
    was not called from a console script's `main` entry point, but from
    other client code, and thus the SystemExit exceptions are muted and
    a `None` value is returned.

def parse_args(args=None):
    """Parse command line arguments and return a dictionary of options
    for ttfautohint.ttfautohint function.

    `args` can be either None, a list of strings, or a single string,
    that is split into individual options with `shlex.split`.

    When `args` is None, the console's default sys.argv are used, and any
    SystemExit exceptions raised by argparse are propagated.

    If args is a string list or a string, it is assumed that the function
    was not called from a console script's `main` entry point, but from
    other client code, and thus the SystemExit exceptions are muted and
    a `None` value is returned.
    """
    import argparse
    from ttfautohint import __version__, libttfautohint
    from ttfautohint.cli import USAGE, DESCRIPTION, EPILOG

    version_string = "ttfautohint-py %s (libttfautohint %s)" % (
        __version__, libttfautohint.version_string)

    if args is None:
        capture_sys_exit = False
    else:
        capture_sys_exit = True
        if isinstance(args, basestring):
            import shlex
            args = shlex.split(args)

    parser = argparse.ArgumentParser(
        prog="ttfautohint",
        usage=USAGE,
        description=DESCRIPTION,
        epilog=EPILOG,
        formatter_class=argparse.RawDescriptionHelpFormatter,
    )
    parser.add_argument(
        "in_file", nargs="?", metavar="IN-FILE", default="-",
        type=stdin_or_input_path_type,
        help="input file (default: standard input)")
    parser.add_argument(
        "out_file", nargs="?", metavar="OUT-FILE", default="-",
        type=stdout_or_output_path_type,
        help="output file (default: standard output)")
    parser.add_argument(
        "--debug", action="store_true", help="print debugging information")

    stem_width_group = parser.add_mutually_exclusive_group(required=False)
    stem_width_group.add_argument(
        "-a", "--stem-width-mode", type=stem_width_mode, metavar="S",
        default=STEM_WIDTH_MODE_OPTIONS,
        help=("select stem width mode for grayscale, GDI ClearType, and DW "
              "ClearType, where S is a string of three letters with possible "
              "values 'n' for natural, 'q' for quantized, and 's' for strong "
              "(default: qsq)"))
    stem_width_group.add_argument(  # deprecated
        "-w", "--strong-stem-width", type=strong_stem_width, metavar="S",
        help=argparse.SUPPRESS)

    parser.add_argument(
        "-c", "--composites", dest="hint_composites", action="store_true",
        help="hint glyph composites also")
    parser.add_argument(
        "-d", "--dehint", action="store_true", help="remove all hints")
    parser.add_argument(
        "-D", "--default-script", metavar="SCRIPT",
        default=USER_OPTIONS["default_script"],
        help="set default OpenType script (default: %(default)s)")
    parser.add_argument(
        "-f", "--fallback-script", metavar="SCRIPT",
        default=USER_OPTIONS["fallback_script"],
        help="set fallback script (default: %(default)s)")
    parser.add_argument(
        "-F", "--family-suffix", metavar="SUFFIX",
        help="append SUFFIX to the family name string(s) in the `name' table")
    parser.add_argument(
        "-G", "--hinting-limit", type=int, metavar="PPEM",
        default=USER_OPTIONS["hinting_limit"],
        help=("switch off hinting above this PPEM value (default: "
              "%(default)s); value 0 means no limit"))
    parser.add_argument(
        "-H", "--fallback-stem-width", type=int, metavar="UNITS",
        default=USER_OPTIONS["fallback_stem_width"],
        help=("set fallback stem width (default: %(default)s font units at "
              "2048 UPEM)"))
    parser.add_argument(
        "-i", "--ignore-restrictions", action="store_true",
        help="override font license restrictions")
    parser.add_argument(
        "-I", "--detailed-info", action="store_true",
        help=("add detailed ttfautohint info to the version string(s) in "
              "the `name' table"))
    parser.add_argument(
        "-l", "--hinting-range-min", type=int, metavar="PPEM",
        default=USER_OPTIONS["hinting_range_min"],
        help="the minimum PPEM value for hint sets (default: %(default)s)")
    parser.add_argument(
        "-m", "--control-file", metavar="FILE",
        help="get control instructions from FILE")
    parser.add_argument(
        "-n", "--no-info", action="store_true",
        help=("don't add ttfautohint info to the version string(s) in the "
              "`name' table"))
    parser.add_argument(
        "-p", "--adjust-subglyphs", action="store_true",
        help="handle subglyph adjustments in exotic fonts")
    parser.add_argument(
        "-r", "--hinting-range-max", type=int, metavar="PPEM",
        default=USER_OPTIONS["hinting_range_max"],
        help="the maximum PPEM value for hint sets (default: %(default)s)")
    parser.add_argument(
        "-R", "--reference", dest="reference_file", metavar="FILE",
        help="derive blue zones from reference font FILE")
    parser.add_argument(
        "-s", "--symbol", action="store_true",
        help="input is symbol font")
    parser.add_argument(
        "-S", "--fallback-scaling", action="store_true",
        help="use fallback scaling, not hinting")
    parser.add_argument(
        "-t", "--ttfa-table", action="store_true", dest="TTFA_info",
        help="add TTFA information table")
    parser.add_argument(
        "-T", "--ttfa-info", dest="show_TTFA_info", action="store_true",
        help="display TTFA table in IN-FILE and exit")
    parser.add_argument(
        "-v", "--verbose", action="store_true",
        help="show progress information")
    parser.add_argument(
        "-V", "--version", action="version",
        version=version_string,
        help="print version information and exit")
    parser.add_argument(
        "-W", "--windows-compatibility", action="store_true",
        help=("add blue zones for `usWinAscent' and `usWinDescent' to avoid "
              "clipping"))
    parser.add_argument(
        "-x", "--increase-x-height", type=int, metavar="PPEM",
        default=USER_OPTIONS["increase_x_height"],
        help=("increase x height for sizes in the range 6<=PPEM<=N; value "
              "0 switches off this feature (default: %(default)s)"))
    parser.add_argument(
        "-X", "--x-height-snapping-exceptions", metavar="STRING",
        default=USER_OPTIONS["x_height_snapping_exceptions"],
        help=('specify a comma-separated list of x-height snapping exceptions'
              ', for example "-9, 13-17, 19" (default: "%(default)s")'))
    parser.add_argument(
        "-Z", "--reference-index", type=int, metavar="NUMBER",
        default=USER_OPTIONS["reference_index"],
        help="face index of reference font (default: %(default)s)")

    try:
        options = vars(parser.parse_args(args))
    except SystemExit:
        if capture_sys_exit:
            return None
        raise

    # if either input/output are interactive, print help and exit
    if (not capture_sys_exit and
            (options["in_file"] is None or options["out_file"] is None)):
        parser.print_help()
        parser.exit(1)

    # check SOURCE_DATE_EPOCH environment variable
    source_date_epoch = os.environ.get("SOURCE_DATE_EPOCH")
    if source_date_epoch:
        try:
            options["epoch"] = int(source_date_epoch)
        except ValueError:
            import warnings
            warnings.warn(
                UserWarning("invalid SOURCE_DATE_EPOCH: %r" % source_date_epoch))

    if options.pop("show_TTFA_info"):
        # TODO use fonttools to dump TTFA table?
        raise NotImplementedError()

    stem_width_options = options.pop("stem_width_mode")
    strong_stem_width_options = options.pop("strong_stem_width")
    if strong_stem_width_options:
        import warnings
        warnings.warn(
            UserWarning("Option '-w' is deprecated! Use option '-a' instead"))
        stem_width_options = strong_stem_width_options
    options.update(stem_width_options)

    return options