src/Pure/System/getopts.scala
author wenzelm
Sat, 27 Feb 2016 16:51:36 +0100
changeset 62434 4630b1748cb3
parent 62432 183c319b26dc
child 62454 38c89353b349
permissions -rw-r--r--
tuned messages;
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
62431
fbccea37091d support for command-line options as in GNU bash;
wenzelm
parents:
diff changeset
     1
/*  Title:      Pure/System/getopts.scala
fbccea37091d support for command-line options as in GNU bash;
wenzelm
parents:
diff changeset
     2
    Author:     Makarius
fbccea37091d support for command-line options as in GNU bash;
wenzelm
parents:
diff changeset
     3
fbccea37091d support for command-line options as in GNU bash;
wenzelm
parents:
diff changeset
     4
Support for command-line options as in GNU bash.
fbccea37091d support for command-line options as in GNU bash;
wenzelm
parents:
diff changeset
     5
*/
fbccea37091d support for command-line options as in GNU bash;
wenzelm
parents:
diff changeset
     6
fbccea37091d support for command-line options as in GNU bash;
wenzelm
parents:
diff changeset
     7
package isabelle
fbccea37091d support for command-line options as in GNU bash;
wenzelm
parents:
diff changeset
     8
fbccea37091d support for command-line options as in GNU bash;
wenzelm
parents:
diff changeset
     9
fbccea37091d support for command-line options as in GNU bash;
wenzelm
parents:
diff changeset
    10
object Getopts
fbccea37091d support for command-line options as in GNU bash;
wenzelm
parents:
diff changeset
    11
{
fbccea37091d support for command-line options as in GNU bash;
wenzelm
parents:
diff changeset
    12
  def apply(usage_text: () => String, option_specs: (String, String => Unit)*): Getopts =
fbccea37091d support for command-line options as in GNU bash;
wenzelm
parents:
diff changeset
    13
  {
fbccea37091d support for command-line options as in GNU bash;
wenzelm
parents:
diff changeset
    14
    val options =
fbccea37091d support for command-line options as in GNU bash;
wenzelm
parents:
diff changeset
    15
      (Map.empty[Char, (Boolean, String => Unit)] /: option_specs) {
fbccea37091d support for command-line options as in GNU bash;
wenzelm
parents:
diff changeset
    16
        case (m, (s, f)) =>
fbccea37091d support for command-line options as in GNU bash;
wenzelm
parents:
diff changeset
    17
          val (a, entry) =
fbccea37091d support for command-line options as in GNU bash;
wenzelm
parents:
diff changeset
    18
            if (s.size == 1) (s(0), (false, f))
fbccea37091d support for command-line options as in GNU bash;
wenzelm
parents:
diff changeset
    19
            else if (s.size == 2 && s.endsWith(":")) (s(0), (true, f))
fbccea37091d support for command-line options as in GNU bash;
wenzelm
parents:
diff changeset
    20
            else error("Bad option specification: " + quote(s))
fbccea37091d support for command-line options as in GNU bash;
wenzelm
parents:
diff changeset
    21
          if (m.isDefinedAt(a)) error("Duplicate option specification: " + quote(a.toString))
fbccea37091d support for command-line options as in GNU bash;
wenzelm
parents:
diff changeset
    22
          else m + (a -> entry)
fbccea37091d support for command-line options as in GNU bash;
wenzelm
parents:
diff changeset
    23
      }
fbccea37091d support for command-line options as in GNU bash;
wenzelm
parents:
diff changeset
    24
    new Getopts(usage_text, options)
fbccea37091d support for command-line options as in GNU bash;
wenzelm
parents:
diff changeset
    25
  }
fbccea37091d support for command-line options as in GNU bash;
wenzelm
parents:
diff changeset
    26
}
fbccea37091d support for command-line options as in GNU bash;
wenzelm
parents:
diff changeset
    27
fbccea37091d support for command-line options as in GNU bash;
wenzelm
parents:
diff changeset
    28
class Getopts private(usage_text: () => String, options: Map[Char, (Boolean, String => Unit)])
fbccea37091d support for command-line options as in GNU bash;
wenzelm
parents:
diff changeset
    29
{
fbccea37091d support for command-line options as in GNU bash;
wenzelm
parents:
diff changeset
    30
  def usage(): Nothing =
fbccea37091d support for command-line options as in GNU bash;
wenzelm
parents:
diff changeset
    31
  {
fbccea37091d support for command-line options as in GNU bash;
wenzelm
parents:
diff changeset
    32
    Console.println(usage_text())
fbccea37091d support for command-line options as in GNU bash;
wenzelm
parents:
diff changeset
    33
    sys.exit(1)
fbccea37091d support for command-line options as in GNU bash;
wenzelm
parents:
diff changeset
    34
  }
fbccea37091d support for command-line options as in GNU bash;
wenzelm
parents:
diff changeset
    35
fbccea37091d support for command-line options as in GNU bash;
wenzelm
parents:
diff changeset
    36
  private def is_option(opt: Char): Boolean = options.isDefinedAt(opt)
fbccea37091d support for command-line options as in GNU bash;
wenzelm
parents:
diff changeset
    37
  private def is_option0(opt: Char): Boolean = is_option(opt) && !options(opt)._1
fbccea37091d support for command-line options as in GNU bash;
wenzelm
parents:
diff changeset
    38
  private def is_option1(opt: Char): Boolean = is_option(opt) && options(opt)._1
62432
183c319b26dc tuned messages;
wenzelm
parents: 62431
diff changeset
    39
  private def print_option(opt: Char): String = quote("-" + opt.toString)
62434
4630b1748cb3 tuned messages;
wenzelm
parents: 62432
diff changeset
    40
  private def option(opt: Char, opt_arg: List[Char]): Unit =
4630b1748cb3 tuned messages;
wenzelm
parents: 62432
diff changeset
    41
    try { options(opt)._2.apply(opt_arg.mkString) }
4630b1748cb3 tuned messages;
wenzelm
parents: 62432
diff changeset
    42
    catch {
4630b1748cb3 tuned messages;
wenzelm
parents: 62432
diff changeset
    43
      case ERROR(msg) =>
4630b1748cb3 tuned messages;
wenzelm
parents: 62432
diff changeset
    44
        cat_error(msg, "The error(s) above occurred in command-line option " + print_option(opt))
4630b1748cb3 tuned messages;
wenzelm
parents: 62432
diff changeset
    45
    }
62431
fbccea37091d support for command-line options as in GNU bash;
wenzelm
parents:
diff changeset
    46
fbccea37091d support for command-line options as in GNU bash;
wenzelm
parents:
diff changeset
    47
  private def getopts(args: List[List[Char]]): List[List[Char]] =
fbccea37091d support for command-line options as in GNU bash;
wenzelm
parents:
diff changeset
    48
    args match {
fbccea37091d support for command-line options as in GNU bash;
wenzelm
parents:
diff changeset
    49
      case List('-', '-') :: rest_args => rest_args
fbccea37091d support for command-line options as in GNU bash;
wenzelm
parents:
diff changeset
    50
      case ('-' :: opt :: rest_opts) :: rest_args if is_option0(opt) && !rest_opts.isEmpty =>
fbccea37091d support for command-line options as in GNU bash;
wenzelm
parents:
diff changeset
    51
        option(opt, Nil); getopts(('-' :: rest_opts) :: rest_args)
fbccea37091d support for command-line options as in GNU bash;
wenzelm
parents:
diff changeset
    52
      case List('-', opt) :: rest_args if is_option0(opt) =>
fbccea37091d support for command-line options as in GNU bash;
wenzelm
parents:
diff changeset
    53
        option(opt, Nil); getopts(rest_args)
fbccea37091d support for command-line options as in GNU bash;
wenzelm
parents:
diff changeset
    54
      case ('-' :: opt :: opt_arg) :: rest_args if is_option1(opt) && !opt_arg.isEmpty =>
fbccea37091d support for command-line options as in GNU bash;
wenzelm
parents:
diff changeset
    55
        option(opt, opt_arg); getopts(rest_args)
fbccea37091d support for command-line options as in GNU bash;
wenzelm
parents:
diff changeset
    56
      case List('-', opt) :: opt_arg :: rest_args if is_option1(opt) =>
fbccea37091d support for command-line options as in GNU bash;
wenzelm
parents:
diff changeset
    57
        option(opt, opt_arg); getopts(rest_args)
fbccea37091d support for command-line options as in GNU bash;
wenzelm
parents:
diff changeset
    58
      case List(List('-', opt)) if is_option1(opt) =>
62432
183c319b26dc tuned messages;
wenzelm
parents: 62431
diff changeset
    59
        Output.error_message("Command-line option " + print_option(opt) + " requires an argument")
62431
fbccea37091d support for command-line options as in GNU bash;
wenzelm
parents:
diff changeset
    60
        usage()
fbccea37091d support for command-line options as in GNU bash;
wenzelm
parents:
diff changeset
    61
      case ('-' :: opt :: _) :: _ if !is_option(opt) =>
62432
183c319b26dc tuned messages;
wenzelm
parents: 62431
diff changeset
    62
        if (opt != '?') Output.error_message("Illegal command-line option " + print_option(opt))
62431
fbccea37091d support for command-line options as in GNU bash;
wenzelm
parents:
diff changeset
    63
        usage()
fbccea37091d support for command-line options as in GNU bash;
wenzelm
parents:
diff changeset
    64
      case _ => args
fbccea37091d support for command-line options as in GNU bash;
wenzelm
parents:
diff changeset
    65
  }
fbccea37091d support for command-line options as in GNU bash;
wenzelm
parents:
diff changeset
    66
fbccea37091d support for command-line options as in GNU bash;
wenzelm
parents:
diff changeset
    67
  def apply(args: List[String]): List[String] = getopts(args.map(_.toList)).map(_.mkString)
fbccea37091d support for command-line options as in GNU bash;
wenzelm
parents:
diff changeset
    68
  def apply(args: Array[String]): List[String] = apply(args.toList)
fbccea37091d support for command-line options as in GNU bash;
wenzelm
parents:
diff changeset
    69
}