1# 2# GetoptLong for Ruby 3# 4# Copyright (C) 1998, 1999, 2000 Motoyuki Kasahara. 5# 6# You may redistribute and/or modify this library under the same license 7# terms as Ruby. 8# 9# See GetoptLong for documentation. 10# 11# Additional documents and the latest version of `getoptlong.rb' can be 12# found at http://www.sra.co.jp/people/m-kasahr/ruby/getoptlong/ 13 14# The GetoptLong class allows you to parse command line options similarly to 15# the GNU getopt_long() C library call. Note, however, that GetoptLong is a 16# pure Ruby implementation. 17# 18# GetoptLong allows for POSIX-style options like <tt>--file</tt> as well 19# as single letter options like <tt>-f</tt> 20# 21# The empty option <tt>--</tt> (two minus symbols) is used to end option 22# processing. This can be particularly important if options have optional 23# arguments. 24# 25# Here is a simple example of usage: 26# 27# require 'getoptlong' 28# 29# opts = GetoptLong.new( 30# [ '--help', '-h', GetoptLong::NO_ARGUMENT ], 31# [ '--repeat', '-n', GetoptLong::REQUIRED_ARGUMENT ], 32# [ '--name', GetoptLong::OPTIONAL_ARGUMENT ] 33# ) 34# 35# dir = nil 36# name = nil 37# repetitions = 1 38# opts.each do |opt, arg| 39# case opt 40# when '--help' 41# puts <<-EOF 42# hello [OPTION] ... DIR 43# 44# -h, --help: 45# show help 46# 47# --repeat x, -n x: 48# repeat x times 49# 50# --name [name]: 51# greet user by name, if name not supplied default is John 52# 53# DIR: The directory in which to issue the greeting. 54# EOF 55# when '--repeat' 56# repetitions = arg.to_i 57# when '--name' 58# if arg == '' 59# name = 'John' 60# else 61# name = arg 62# end 63# end 64# end 65# 66# if ARGV.length != 1 67# puts "Missing dir argument (try --help)" 68# exit 0 69# end 70# 71# dir = ARGV.shift 72# 73# Dir.chdir(dir) 74# for i in (1..repetitions) 75# print "Hello" 76# if name 77# print ", #{name}" 78# end 79# puts 80# end 81# 82# Example command line: 83# 84# hello -n 6 --name -- /tmp 85# 86class GetoptLong 87 # 88 # Orderings. 89 # 90 ORDERINGS = [REQUIRE_ORDER = 0, PERMUTE = 1, RETURN_IN_ORDER = 2] 91 92 # 93 # Argument flags. 94 # 95 ARGUMENT_FLAGS = [NO_ARGUMENT = 0, REQUIRED_ARGUMENT = 1, 96 OPTIONAL_ARGUMENT = 2] 97 98 # 99 # Status codes. 100 # 101 STATUS_YET, STATUS_STARTED, STATUS_TERMINATED = 0, 1, 2 102 103 # 104 # Error types. 105 # 106 class Error < StandardError; end 107 class AmbiguousOption < Error; end 108 class NeedlessArgument < Error; end 109 class MissingArgument < Error; end 110 class InvalidOption < Error; end 111 112 # 113 # Set up option processing. 114 # 115 # The options to support are passed to new() as an array of arrays. 116 # Each sub-array contains any number of String option names which carry 117 # the same meaning, and one of the following flags: 118 # 119 # GetoptLong::NO_ARGUMENT :: Option does not take an argument. 120 # 121 # GetoptLong::REQUIRED_ARGUMENT :: Option always takes an argument. 122 # 123 # GetoptLong::OPTIONAL_ARGUMENT :: Option may or may not take an argument. 124 # 125 # The first option name is considered to be the preferred (canonical) name. 126 # Other than that, the elements of each sub-array can be in any order. 127 # 128 def initialize(*arguments) 129 # 130 # Current ordering. 131 # 132 if ENV.include?('POSIXLY_CORRECT') 133 @ordering = REQUIRE_ORDER 134 else 135 @ordering = PERMUTE 136 end 137 138 # 139 # Hash table of option names. 140 # Keys of the table are option names, and their values are canonical 141 # names of the options. 142 # 143 @canonical_names = Hash.new 144 145 # 146 # Hash table of argument flags. 147 # Keys of the table are option names, and their values are argument 148 # flags of the options. 149 # 150 @argument_flags = Hash.new 151 152 # 153 # Whether error messages are output to $stderr. 154 # 155 @quiet = FALSE 156 157 # 158 # Status code. 159 # 160 @status = STATUS_YET 161 162 # 163 # Error code. 164 # 165 @error = nil 166 167 # 168 # Error message. 169 # 170 @error_message = nil 171 172 # 173 # Rest of catenated short options. 174 # 175 @rest_singles = '' 176 177 # 178 # List of non-option-arguments. 179 # Append them to ARGV when option processing is terminated. 180 # 181 @non_option_arguments = Array.new 182 183 if 0 < arguments.length 184 set_options(*arguments) 185 end 186 end 187 188 # 189 # Set the handling of the ordering of options and arguments. 190 # A RuntimeError is raised if option processing has already started. 191 # 192 # The supplied value must be a member of GetoptLong::ORDERINGS. It alters 193 # the processing of options as follows: 194 # 195 # <b>REQUIRE_ORDER</b> : 196 # 197 # Options are required to occur before non-options. 198 # 199 # Processing of options ends as soon as a word is encountered that has not 200 # been preceded by an appropriate option flag. 201 # 202 # For example, if -a and -b are options which do not take arguments, 203 # parsing command line arguments of '-a one -b two' would result in 204 # 'one', '-b', 'two' being left in ARGV, and only ('-a', '') being 205 # processed as an option/arg pair. 206 # 207 # This is the default ordering, if the environment variable 208 # POSIXLY_CORRECT is set. (This is for compatibility with GNU getopt_long.) 209 # 210 # <b>PERMUTE</b> : 211 # 212 # Options can occur anywhere in the command line parsed. This is the 213 # default behavior. 214 # 215 # Every sequence of words which can be interpreted as an option (with or 216 # without argument) is treated as an option; non-option words are skipped. 217 # 218 # For example, if -a does not require an argument and -b optionally takes 219 # an argument, parsing '-a one -b two three' would result in ('-a','') and 220 # ('-b', 'two') being processed as option/arg pairs, and 'one','three' 221 # being left in ARGV. 222 # 223 # If the ordering is set to PERMUTE but the environment variable 224 # POSIXLY_CORRECT is set, REQUIRE_ORDER is used instead. This is for 225 # compatibility with GNU getopt_long. 226 # 227 # <b>RETURN_IN_ORDER</b> : 228 # 229 # All words on the command line are processed as options. Words not 230 # preceded by a short or long option flag are passed as arguments 231 # with an option of '' (empty string). 232 # 233 # For example, if -a requires an argument but -b does not, a command line 234 # of '-a one -b two three' would result in option/arg pairs of ('-a', 'one') 235 # ('-b', ''), ('', 'two'), ('', 'three') being processed. 236 # 237 def ordering=(ordering) 238 # 239 # The method is failed if option processing has already started. 240 # 241 if @status != STATUS_YET 242 set_error(ArgumentError, "argument error") 243 raise RuntimeError, 244 "invoke ordering=, but option processing has already started" 245 end 246 247 # 248 # Check ordering. 249 # 250 if !ORDERINGS.include?(ordering) 251 raise ArgumentError, "invalid ordering `#{ordering}'" 252 end 253 if ordering == PERMUTE && ENV.include?('POSIXLY_CORRECT') 254 @ordering = REQUIRE_ORDER 255 else 256 @ordering = ordering 257 end 258 end 259 260 # 261 # Return ordering. 262 # 263 attr_reader :ordering 264 265 # 266 # Set options. Takes the same argument as GetoptLong.new. 267 # 268 # Raises a RuntimeError if option processing has already started. 269 # 270 def set_options(*arguments) 271 # 272 # The method is failed if option processing has already started. 273 # 274 if @status != STATUS_YET 275 raise RuntimeError, 276 "invoke set_options, but option processing has already started" 277 end 278 279 # 280 # Clear tables of option names and argument flags. 281 # 282 @canonical_names.clear 283 @argument_flags.clear 284 285 arguments.each do |arg| 286 if !arg.is_a?(Array) 287 raise ArgumentError, "the option list contains non-Array argument" 288 end 289 290 # 291 # Find an argument flag and it set to `argument_flag'. 292 # 293 argument_flag = nil 294 arg.each do |i| 295 if ARGUMENT_FLAGS.include?(i) 296 if argument_flag != nil 297 raise ArgumentError, "too many argument-flags" 298 end 299 argument_flag = i 300 end 301 end 302 303 raise ArgumentError, "no argument-flag" if argument_flag == nil 304 305 canonical_name = nil 306 arg.each do |i| 307 # 308 # Check an option name. 309 # 310 next if i == argument_flag 311 begin 312 if !i.is_a?(String) || i !~ /^-([^-]|-.+)$/ 313 raise ArgumentError, "an invalid option `#{i}'" 314 end 315 if (@canonical_names.include?(i)) 316 raise ArgumentError, "option redefined `#{i}'" 317 end 318 rescue 319 @canonical_names.clear 320 @argument_flags.clear 321 raise 322 end 323 324 # 325 # Register the option (`i') to the `@canonical_names' and 326 # `@canonical_names' Hashes. 327 # 328 if canonical_name == nil 329 canonical_name = i 330 end 331 @canonical_names[i] = canonical_name 332 @argument_flags[i] = argument_flag 333 end 334 raise ArgumentError, "no option name" if canonical_name == nil 335 end 336 return self 337 end 338 339 # 340 # Set/Unset `quiet' mode. 341 # 342 attr_writer :quiet 343 344 # 345 # Return the flag of `quiet' mode. 346 # 347 attr_reader :quiet 348 349 # 350 # `quiet?' is an alias of `quiet'. 351 # 352 alias quiet? quiet 353 354 # 355 # Explicitly terminate option processing. 356 # 357 def terminate 358 return nil if @status == STATUS_TERMINATED 359 raise RuntimeError, "an error has occurred" if @error != nil 360 361 @status = STATUS_TERMINATED 362 @non_option_arguments.reverse_each do |argument| 363 ARGV.unshift(argument) 364 end 365 366 @canonical_names = nil 367 @argument_flags = nil 368 @rest_singles = nil 369 @non_option_arguments = nil 370 371 return self 372 end 373 374 # 375 # Returns true if option processing has terminated, false otherwise. 376 # 377 def terminated? 378 return @status == STATUS_TERMINATED 379 end 380 381 # 382 # Set an error (a protected method). 383 # 384 def set_error(type, message) 385 $stderr.print("#{$0}: #{message}\n") if !@quiet 386 387 @error = type 388 @error_message = message 389 @canonical_names = nil 390 @argument_flags = nil 391 @rest_singles = nil 392 @non_option_arguments = nil 393 394 raise type, message 395 end 396 protected :set_error 397 398 # 399 # Examine whether an option processing is failed. 400 # 401 attr_reader :error 402 403 # 404 # `error?' is an alias of `error'. 405 # 406 alias error? error 407 408 # Return the appropriate error message in POSIX-defined format. 409 # If no error has occurred, returns nil. 410 # 411 def error_message 412 return @error_message 413 end 414 415 # 416 # Get next option name and its argument, as an Array of two elements. 417 # 418 # The option name is always converted to the first (preferred) 419 # name given in the original options to GetoptLong.new. 420 # 421 # Example: ['--option', 'value'] 422 # 423 # Returns nil if the processing is complete (as determined by 424 # STATUS_TERMINATED). 425 # 426 def get 427 option_name, option_argument = nil, '' 428 429 # 430 # Check status. 431 # 432 return nil if @error != nil 433 case @status 434 when STATUS_YET 435 @status = STATUS_STARTED 436 when STATUS_TERMINATED 437 return nil 438 end 439 440 # 441 # Get next option argument. 442 # 443 if 0 < @rest_singles.length 444 argument = '-' + @rest_singles 445 elsif (ARGV.length == 0) 446 terminate 447 return nil 448 elsif @ordering == PERMUTE 449 while 0 < ARGV.length && ARGV[0] !~ /^-./ 450 @non_option_arguments.push(ARGV.shift) 451 end 452 if ARGV.length == 0 453 terminate 454 return nil 455 end 456 argument = ARGV.shift 457 elsif @ordering == REQUIRE_ORDER 458 if (ARGV[0] !~ /^-./) 459 terminate 460 return nil 461 end 462 argument = ARGV.shift 463 else 464 argument = ARGV.shift 465 end 466 467 # 468 # Check the special argument `--'. 469 # `--' indicates the end of the option list. 470 # 471 if argument == '--' && @rest_singles.length == 0 472 terminate 473 return nil 474 end 475 476 # 477 # Check for long and short options. 478 # 479 if argument =~ /^(--[^=]+)/ && @rest_singles.length == 0 480 # 481 # This is a long style option, which start with `--'. 482 # 483 pattern = $1 484 if @canonical_names.include?(pattern) 485 option_name = pattern 486 else 487 # 488 # The option `option_name' is not registered in `@canonical_names'. 489 # It may be an abbreviated. 490 # 491 matches = [] 492 @canonical_names.each_key do |key| 493 if key.index(pattern) == 0 494 option_name = key 495 matches << key 496 end 497 end 498 if 2 <= matches.length 499 set_error(AmbiguousOption, "option `#{argument}' is ambiguous between #{matches.join(', ')}") 500 elsif matches.length == 0 501 set_error(InvalidOption, "unrecognized option `#{argument}'") 502 end 503 end 504 505 # 506 # Check an argument to the option. 507 # 508 if @argument_flags[option_name] == REQUIRED_ARGUMENT 509 if argument =~ /=(.*)$/ 510 option_argument = $1 511 elsif 0 < ARGV.length 512 option_argument = ARGV.shift 513 else 514 set_error(MissingArgument, 515 "option `#{argument}' requires an argument") 516 end 517 elsif @argument_flags[option_name] == OPTIONAL_ARGUMENT 518 if argument =~ /=(.*)$/ 519 option_argument = $1 520 elsif 0 < ARGV.length && ARGV[0] !~ /^-./ 521 option_argument = ARGV.shift 522 else 523 option_argument = '' 524 end 525 elsif argument =~ /=(.*)$/ 526 set_error(NeedlessArgument, 527 "option `#{option_name}' doesn't allow an argument") 528 end 529 530 elsif argument =~ /^(-(.))(.*)/ 531 # 532 # This is a short style option, which start with `-' (not `--'). 533 # Short options may be catenated (e.g. `-l -g' is equivalent to 534 # `-lg'). 535 # 536 option_name, ch, @rest_singles = $1, $2, $3 537 538 if @canonical_names.include?(option_name) 539 # 540 # The option `option_name' is found in `@canonical_names'. 541 # Check its argument. 542 # 543 if @argument_flags[option_name] == REQUIRED_ARGUMENT 544 if 0 < @rest_singles.length 545 option_argument = @rest_singles 546 @rest_singles = '' 547 elsif 0 < ARGV.length 548 option_argument = ARGV.shift 549 else 550 # 1003.2 specifies the format of this message. 551 set_error(MissingArgument, "option requires an argument -- #{ch}") 552 end 553 elsif @argument_flags[option_name] == OPTIONAL_ARGUMENT 554 if 0 < @rest_singles.length 555 option_argument = @rest_singles 556 @rest_singles = '' 557 elsif 0 < ARGV.length && ARGV[0] !~ /^-./ 558 option_argument = ARGV.shift 559 else 560 option_argument = '' 561 end 562 end 563 else 564 # 565 # This is an invalid option. 566 # 1003.2 specifies the format of this message. 567 # 568 if ENV.include?('POSIXLY_CORRECT') 569 set_error(InvalidOption, "invalid option -- #{ch}") 570 else 571 set_error(InvalidOption, "invalid option -- #{ch}") 572 end 573 end 574 else 575 # 576 # This is a non-option argument. 577 # Only RETURN_IN_ORDER falled into here. 578 # 579 return '', argument 580 end 581 582 return @canonical_names[option_name], option_argument 583 end 584 585 # 586 # `get_option' is an alias of `get'. 587 # 588 alias get_option get 589 590 # Iterator version of `get'. 591 # 592 # The block is called repeatedly with two arguments: 593 # The first is the option name. 594 # The second is the argument which followed it (if any). 595 # Example: ('--opt', 'value') 596 # 597 # The option name is always converted to the first (preferred) 598 # name given in the original options to GetoptLong.new. 599 # 600 def each 601 loop do 602 option_name, option_argument = get_option 603 break if option_name == nil 604 yield option_name, option_argument 605 end 606 end 607 608 # 609 # `each_option' is an alias of `each'. 610 # 611 alias each_option each 612end 613