def code(*t)
owner = t[0]
mod = t[1]
code = "\n"
flag = @flag
clump = owner.clump
i = 0
nocasei = ((Getopt::Declare::nocase || @nocase) ? 'i' : '')
code << " catch(:paramout) do\n while "
code += !@repeatable? "!_FOUND_['" + self.foundid + "']" : "true"
if (flag && (clump==1 && flag !~ /\A[^a-z0-9]+[a-z0-9]\Z/i ||
(clump<3 && @args.size > 0 )))
code << ' and !_lastprefix'
end
code "\n if flag != ''\n # This boundary is to handle -- option, so that if user uses\n # --foo and --foo is not a flag, it does not become\n # -- and unused: 'foo', but an error saying flag '--foo' not defined.\n boundary = ''\n boundary = '(\\s+|\\Z)' if flag =~ /^(--|-|\\+|\\+\\+)$/\n\n code << '\n _args && _pos = gindex( _args, /\\G[\\s|\\0]*' + \n Regexp::quote(flag) + boundary + '/' + nocasei + \", _pos) or throw(:paramout) \n unless @_errormsg\n @_errormsg = %q|incorrect specification of '\" + flag + \"' parameter|\n end\n\"\n elsif ( ScalarArg::stdtype(@args[0].type)||'') !~ /\\%F/\n code << \"\\n throw(:paramout) if @_errormsg\\n\"\n end\n\n\n code << \"\\n _PARAM_ = '\" + self.name + \"'\\n\"\n\n\n trailer = []\n i = @args.size-1\n while i > 0\n trailer[i-1] = @args[i].trailer\n trailer[i-1] = trailer[i] unless trailer[i-1]\n i -= 1\n end # while i\n\n if @args\n code << \"\\n\"+' _args && _pos = gindex( _args, /\\G'\n\n @args.each_with_index { |arg, i|\n code << arg.ows(arg.matcher(trailer[i]))\n }\n\n code << '/x' + nocasei + \", _pos ) or throw(:paramout)\\n\"\n end # if @args\n\n @args.each_with_index { |arg, i|\n code << arg.code(i,mod) #, $flag ????\n }\n\n if flag\n mutexlist = owner.mutex[flag] ? \n ( owner.mutex[flag].map {|i| \"'\#{i}'\"} ).join(',') : ''\n\n code << \"\n if _invalid.has_key?('\#{flag}')\n @_errormsg = %q|parameter '\#{flag}' not allowed with parameter '| + _invalid['\#{flag}'] + %q|'|\n throw(:paramout)\n else\n for i in [\#{mutexlist}]\n _invalid[i] = '\#{flag}'\n end\n end #if/then\n\n\"\n end\n\n\n\n for action in @actions\n #action.sub!( /(\\s*\\{)/, '\\1 module '+mod ) # @TODO\n code << \"\\n \" + action + \"\\n\"\n end\n\n if flag && @items==0\n code << \"\\n @cache['\#{flag}'] = '\#{flag}'\\n\"\n if @ditto\n code << \"\\n @cache['\#{@ditto.flag}'] = '\#{flag}'\\n\"\n end\n end\n\n if @items > 1\n code << \" @cache['\#{self.name}'] = {} unless @cache['\#{self.name}'].kind_of?(Hash)\\n\"\n if @ditto\n code << \"\\n @cache['\#{@ditto.name}'] = {} unless @cache['\#{@ditto.name}'].kind_of?(Hash)\\n\"\n end\n end\n\n for subarg in @args\n code << subarg.cachecode(self.name,@items)\n if ditto\n code << subarg.cachecode(@ditto.name,@items)\n end\n end\n\n if flag =~ /\\A([^a-z0-9]+)/i\n code << ' _lastprefix = \"'+ Regexp::quote(\"\#$1\") + '\"' + \"\\n\"\n else\n code << \" _lastprefix = nil\\n\"\n end\n\n code << \"\n _FOUND_['\"+ self.foundid + \"'] = 1\n throw :arg if _pos > 0\n _nextpos = _args.size\n throw :alldone\n end # catch(:param)\n end # begin\n end # while\n end # catch(:paramout)\n\"\n\n code\n end\n\n # Return name of argument, which can be flag's name or variable's name\n def name\n return @flag unless @flag.empty?\n for i in @args\n return \"<\#{i.name}>\" if i.respond_to?(:name)\n end\n raise \"Unknown flag name for parameter \#{self.desc}\"\n end\n\n # Return foundid of argument, which can be flag's name or variable's name\n def foundid\n return @foundid || self.name\n end\n\n end # Arg\n\n\n private\n\n class << self\n @nocase = false\n attr_accessor :nocase\n end\n\n #\n # This is an additional function added to the class to simulate Perl's\n # pos() \\G behavior and m///g\n #\n # It performs a regex match, and returns the last index position of the \n # match or nil. On successive invocations, it allows doing regex matches\n # NOT from the beginning of the string easily.\n #\n # Class Array @@m stores the list of matches, as \#$1 and similar \n # variables have short lifespan in ruby, unlike perl.\n #\n def gindex(str, re, pos)\n @@m.clear()\n if pos = str.index( re, pos )\n l = $&.size # length of match\n if l > 0\n @@m[0] = \"\#$1\"\n @@m[1] = \"\#$2\"\n @@m[2] = \"\#$3\"\n @@m[3] = \"\#$4\"\n @@m[4] = \"\#$5\"\n @@m[5] = \"\#$6\"\n @@m[6] = \"\#$7\"\n @@m[7] = \"\#$8\"\n @@m[8] = \"\#$9\"\n pos += l\n end\n end\n pos\n end\n\n # Given an array or hash, flatten them to a string\n def flatten(val, nested = nil)\n case val\n when Array\n return val.map{ |i| flatten(i,1) }.join(\" \")\n when Hash\n return val.keys.map{ |i| nested || \n i =~ /^-/ ? [i, flatten(val[i],1)] : \n [flatten(val[i],1)] }.join(\" \")\n else\n return val\n end\n end\n\n # Read the next line from stdin\n def _get_nextline\n $stdin.readline\n end\n\n # For each file provided and found, read it in\n def _load_sources( _get_nextline, files )\n text = ''\n found = []\n \n for i in files\n begin\n f = File.open(i,\"r\")\n rescue\n next\n end\n\n if f.tty?\n found.push( '<STDIN>' )\n _get_nextline = method(:_get_nextline)\n else\n found.push( i );\n t = f.readlines.join(' ')\n t.tr!('\\t\\n',' ')\n text += t\n end\n end\n\n return nil unless found.size > 0\n text = $stdin.readline if text.empty?\n return [text, found.join(' or ')]\n end\n\n\n # Check parameter description for special options\n def _infer(desc, arg, mutex)\n while desc.sub!(/\\[\\s*mutex:\\s*(.*?)\\]/i,\"\")\n _mutex(mutex, \"\#$1\".split(' '))\n end\n\n if desc =~ /\\[\\s*no\\s*case\\s*\\]/i\n if arg\n arg.nocase = true\n else \n nocase = true\n end\n end\n\n if !arg.nil?\n if desc =~ /.*\\[\\s*excludes:\\s*(.*?)\\]/i\n _exclude(mutex, arg.name, (\"\#$1\".split(' ')))\n end\n\n if desc =~ /.*\\[\\s*requires:\\s*(.*?)\\s*\\]/i\n arg.requires = \"\#$1\"\n end\n\n arg.required = ( desc =~ /\\[\\s*required\\s*\\]/i )\n\n arg.repeatable = ( desc =~ /\\[\\s*repeatable\\s*\\]/i )\n end\n\n _typedef(desc) while desc.sub!(/.*?\\[\\s*pvtype:\\s*/,\"\")\n\n end\n\n\n\n # Extract a new type from the description and add it to the list\n # of standard types\n def _typedef(desc)\n se = DelimScanner::new( desc )\n tmp = se.scanQuotelike\n\n name = nil\n name, desc = tmp[:delimText], tmp[:suffix] if tmp\n\n unless name\n desc.sub!(/\\A\\s*([^\\] \\t\\n]+)/,\"\") and name = \"\#$1\"\n end\n\n raise \"Error: bad type directive (missing type name): [pvtype: \" +\n desc[0,desc.index(']')||20] + \"....\\n\" unless name\n\n se = DelimScanner::new( desc )\n tmp = se.scanQuotelike('\\s*:?\\s*')\n\n # @TODO What is element 2 of extract_quotelike? :trail is a fake here\n # pat,desc,ind = (extract_quotelike(desc,'\\s*:?\\s*'))[5,1,2]\n pat = ind = nil\n pat, desc, ind = tmp[:match], tmp[:suffix], tmp[:prefix] if tmp\n pat = pat[1..-2] if pat\n\n unless pat\n desc.sub!(/\\A\\s*(:?)\\s*([^\\] \\t\\n]+)/,\"\") and pat = \"\#$2\" and ind = \"\#$1\"\n end\n\n pat = '' unless pat\n\n \n se = DelimScanner::new( desc )\n action = se.extractCodeblock || ''\n\n desc.sub!( Regexp::quote(action).to_re, '' )\n action = action[1..-2]\n\n raise \"Error: bad type directive (expected closing ']' but found \" +\n \"'\#$1' instead): [pvtype: \#{name} \" + (pat ? \"/\#{pat}/\" : '') +\n \" action:\#{action} \#$1\#$2....\\n\" if desc =~ /\\A\\s*([^\\] \\t\\n])(\\S*)/\n \n \n Getopt::Declare::ScalarArg::addtype(name,pat,action,ind=~/:/)\n end\n\n # Handle quote replacements for [ditto] flag\n def _ditto(originalflag, originaldesc, extra)\n if originaldesc =~ /\\n.*\\n/\n originaldesc = \"Same as \#{originalflag} \"\n else\n originaldesc.chomp\n originaldesc.gsub!(/\\S/,'\"')\n while originaldesc.gsub!(/\"(\"+)\"/,' \\1 ')\n end\n originaldesc.gsub!(/\"\"/,'\" ')\n end\n\n \"\#{originaldesc}\#{extra}\\n\"\n end\n\n # Check mutex conditions\n def _mutex(mref, mutexlist)\n for flag in mutexlist\n mref[flag] = [] unless mref[flag]\n for otherflag in mutexlist\n next if flag == otherflag\n mref[flag].push( otherflag )\n end\n end\n end\n\n # Check exclude conditions\n def _exclude(mref, excluded, mutexlist)\n for flag in mutexlist\n unless flag == excluded\n mref[flag] = [] unless mref[flag]\n mref[excluded] = [] unless mref[excluded]\n mref[excluded].push( flag )\n mref[flag].push( excluded )\n end\n end\n end\n\n # Returns a regex to match a single argument line\n def re_argument\n /\\A(.*?\\S.*?\#{@@separator})(.*?\\n)/\n end\n\n # Returns a regex to keep matching a multi-line description\n # for an argument.\n def re_more_desc\n /\\A((?![ \\t]*(\\{|\\n)|.*?\\S.*?\#{@@separator}.*?\\S).*?\\S.*\\n)/\n end\n\n public\n\n # Constructor\n def initialize(*opts)\n @cache = nil\n\n Getopt::Declare::Arg::clear\n\n # HANDLE SHORT-CIRCUITS\n return if opts.size==2 && (!opts[1] || opts[1] == '-SKIP') \n\n grammar, source = opts\n\n if grammar.nil?\n raise \"Error: No grammar description provided.\"\n end\n\n ### REMOVED PREDEF GRAMMAR AS IT WAS NOT DOCUMENTED NOR \n ### WORKING IN PERL'S Declare.pm VERSION.\n\n # PRESERVE ESCAPED '['s\n grammar.gsub!(/\\\\\\[/,\"\\255\")\n\n # MAKE SURE GRAMMAR ENDS WITH A NEWLINE.\n grammar.sub!(/([^\\n])\\Z/,'\\1'+\"\\n\")\n\n @usage = grammar.dup\n\n # SET-UP\n i = grammar\n _args = []\n _mutex = {}\n _strict = false\n _all_repeatable = false\n _lastdesc = nil\n arg = nil\n Getopt::Declare::nocase = false\n Getopt::Declare::ScalarArg::_reset_stdtype\n\n\n # CONSTRUCT GRAMMAR\n while i.length > 0\n\n # COMMENT:\n i.sub!(/\\A[ \\t]*#.*\\n/,\"\") and next\n\n\n # TYPE DIRECTIVE:\n se = DelimScanner::new( i )\n\n if i =~ /\\A\\s*\\[\\s*pvtype:/ \n _action = se.extractBracketed(\"[\")\n if _action\n i.sub!( Regexp::quote( _action ).to_re, \"\" ) ### @GGA: added\n i.sub!(/\\A[ \\t]*\\n/,\"\") ### @GGA: added\n _action.sub!(/.*?\\[\\s*pvtype:\\s*/,\"\")\n _typedef(_action)\n next\n end # if\n end\n\n # ACTION \n codeblockDelimiters = {\n '{' => '}',\n }\n\n _action = se.extractCodeblock(codeblockDelimiters)\n if _action\n i.sub!( Regexp::quote(_action ).to_re, \"\" )\n i.sub!(/\\A[ \\t]*\\n/,\"\")\n _action = _action[1..-2]\n\n if !valid_syntax?( _action )\n raise \"Error: bad action in Getopt::Declare specification:\" +\n \"\\n\\n\#{_action}\\n\\n\\n\"\n end\n\n if _args.length == 0\n raise \"Error: unattached action in Getopt::Declare specification:\\n\#{_action}\\n\" +\n \"\\t(did you forget the tab after the preceding parameter specification?)\\n\"\n end\n\n _args.last.actions.push( _action )\n next\n elsif i =~ /\\A(\\s*[{].*)/\n raise \"Error: incomplete action in Getopt::Declare specification:\\n$1.....\\n\" +\n \"\\t(did you forget a closing '}'?)\\n\"\n end\n\n\n # ARG + DESC:\n if i.sub!(re_argument,\"\")\n spec = \"\#$1\".strip\n desc = \"\#$2\"\n _strict ||= desc =~ /\\[\\s*strict\\s*\\]/\n\n while i.sub!(re_more_desc,\"\")\n desc += \"\#$1\"\n end\n \n ditto = nil\n if _lastdesc and desc.sub!(/\\A\\s*\\[\\s*ditto\\s*\\]/,_lastdesc)\n ditto = arg\n else\n _lastdesc = desc\n end\n\n # Check for GNU spec line like: -d, --debug\n arg = nil\n if spec =~ /(-[\\w_\\d]+),\\s+(--?[\\w_\\d]+)(\\s+.*)?/\n specs = [\"\#$1\#$3\", \"\#$2\#$3\"]\n specs.each { |spec|\n arg = Arg.new(spec,desc,ditto)\n _args.push( arg )\n _infer(desc, arg, _mutex)\n ditto = arg\n }\n else\n arg = Arg.new(spec,desc,ditto)\n _args.push( arg )\n _infer(desc, arg, _mutex)\n end\n\n\n next\n end\n\n # OTHERWISE: DECORATION\n i.sub!(/((?:(?!\\[\\s*pvtype:).)*)(\\n|(?=\\[\\s*pvtype:))/,\"\")\n decorator = \"\#$1\"\n _strict ||= decorator =~ /\\[\\s*strict\\s*\\]/\n _infer(decorator, nil, _mutex)\n\n _all_repeatable = true if decorator =~ /\\[\\s*repeatable\\s*\\]/\n @@debug = true if decorator =~ /\\[\\s*debug\\s*\\]/\n\n end # while i.length\n\n\n\n _lastactions = nil\n for i in _args\n if _lastactions && i.ditto && i.actions.size == 0\n i.actions = _lastactions\n else\n _lastactions = i.actions\n end\n\n if _all_repeatable\n i.repeatable = 1\n end\n end\n\n # Sort flags based on criteria described in docs\n # Sadly, this cannot be reduced to sort_by\n _args = _args.sort() { |a,b|\n cond1 = ( b.flag.size <=> a.flag.size )\n cond2 = ( b.flag == a.flag and ( b.args.size <=> a.args.size ) )\n cond3 = ( a.id <=> b.id )\n cond1 = nil if cond1 == 0\n cond2 = nil if cond2 == 0\n cond1 or cond2 or cond3\n }\n\n # Handle clump\n clump = (@usage =~ /\\[\\s*cluster:\\s*none\\s*\\]/i) ? 0 :\n (@usage =~ /\\[\\s*cluster:\\s*singles?\\s*\\]/i) ? 1 :\n (@usage =~ /\\[\\s*cluster:\\s*flags?\\s*\\]/i) ? 2 :\n (@usage =~ /\\[\\s*cluster:\\s*any\\s*\\]/i) ? 3 :\n (@usage =~ /\\[\\s*cluster:(.*)\\s*\\]/i) ? \"r\" : 3\n raise \"Error: unknown clustering mode: [cluster:\#$1]\\n\" if clump == \"r\"\n\n # CONSTRUCT OBJECT ITSELF\n @args = _args\n @mutex = _mutex\n @helppat = Arg::helppat()\n @verspat = Arg::versionpat()\n\n @strict = _strict\n @clump = clump\n @source = ''\n @tight = @usage =~ /\\[\\s*tight\\s*\\]/i\n @caller = caller()\n\n # VESTIGAL DEBUGGING CODE\n if @@debug\n f = File.new(\".CODE.rb\",\"w\") and\n f.puts( code() ) and\n f.close() \n end\n\n # DO THE PARSE (IF APPROPRIATE)\n if opts.size == 2\n return nil unless parse(source)\n else\n return nil unless parse()\n end\n\n end # initialize\n\n\n # Parse the parameter description and in some cases,\n # optionally eval it, too.\n def parse(*opts)\n source = opts[0]\n _args = nil\n _get_nextline = proc { nil }\n\n if source\n case source\n when Method\n _get_nextline = source\n _args = _get_nextline.call(self)\n source = '[METHOD]'\n when Proc\n _get_nextline = source\n _args = _get_nextline.call(self)\n source = '[PROC]'\n when IO\n if source.fileno > 0 && source.tty?\n _get_nextline = method(:_get_nextline)\n _args = $stdin.readline\n source = '<STDIN>'\n else\n _args = source.readlines.join(' ')\n _args.tr!('\\t\\n',' ')\n end\n when :build, :skip\n return 0\n when Array\n if source.length() == 1 && !source[0] ||\n source[0] == \"-BUILD\" ||\n source[0] == \"-SKIP\"\n return 0\n elsif source.length() == 2 && source[0] == \"-ARGV\"\n if !source[1] or !source[1] === Array\n raise 'Error: parse([\"-ARGV\"]) not passed an array as second parameter.'\n end\n _args = source[1].map { |i| i.tr( \" \\t\\n\", \"\\0\\0\\0\" ) }.join(' ')\n source = '<ARRAY>'\n elsif source.length() == 1 && source[0] == \"-STDIN\"\n _get_nextline = method(:_get_nextline)\n _args = $stdin.readline\n source = '<STDIN>'\n elsif source.length() == 1 && source[0] == '-CONFIG'\n progname = \"\#{$0}rc\"\n progname.sub!(%r#.*/#,'')\n home = ENV['HOME'] || ''\n _args, source = _load_sources( _get_nextline,\n [ home+\"/.\#{progname}\",\n \".\#{progname}\" ] )\n else\n # Bunch of files to load passed to parse()\n _args, source = _load_sources( _get_nextline, source )\n end\n when String # else/case LITERAL STRING TO PARSE\n _args = source.dup\n source = source[0,7] + '...' if source && source.length() > 7\n source = \"\\\"\#{source[0..9]}\\\"\"\n else\n raise \"Unknown source type for Getopt::Declare::parse\"\n end # case\n return 0 unless _args\n source = \" (in \#{source})\"\n else\n _args = ARGV.map { |i| i.tr( \" \\t\\n\", \"\\0\\0\\0\" ) }.join(' ')\n source = ''\n end\n\n @source = source\n begin\n err = eval( code(@caller) )\n if $@\n # oops, something wrong... exit\n puts \"\#{$!}: \#{$@.inspect}\"\n exit(1)\n end\n if !err\n exit(1)\n end\n rescue\n raise\n end\n\n\n true\n end\n\n def type(*t)\n Getopt::Declare::ScalarArg::addtype(t)\n end\n\n # Print out version information and maybe exit\n def version(*t)\n prog = \"\#{$0}\"\n begin\n filedate = File.stat( prog ).mtime.localtime()\n rescue\n filedate = 'Unknown date'\n end\n prog.sub!(%r#.*/#,'')\n r = ''\n if defined?($VERSION)\n r << \"\\n\#{prog}: version \#{$VERSION} (\#{filedate})\\n\\n\"\n else\n r << \"\\n\#{prog}: version dated \#{filedate}\\n\\n\"\n end\n\n if t.empty?\n return r\n else\n puts r\n exit t[0]\n end \n end\n\n # Print out usage information\n def usage(*opt)\n\n t = @usage\n\n lastflag = nil\n lastdesc = nil\n usage = ''\n\n while !t.empty?\n\n # COMMENT:\n t.sub!(/\\A[ \\t]*#.*\\n/,\".\") and next\n\n # TYPE DIRECTIVE:\n se = DelimScanner::new( t )\n\n if t =~ /\\A\\s*\\[\\s*pvtype:/\n if action = se.extractBracketed(\"[\")\n t.sub!(Regexp::quote( action ).to_re,'')\n t.sub!(/\\A[ \\t]*\\n/,\"\") \n next\n end\n end\n\n # ACTION\n codeblockDelimiters = {\n '{' => '}'\n }\n se = DelimScanner::new( t )\n if action = se.extractCodeblock(codeblockDelimiters)\n t.sub!(Regexp::quote( action ).to_re,'')\n t.sub!(/\\A[ \\t]*\\n/,\"\")\n decfirst = 0 unless !decfirst.nil?\n next\n end\n\n\n # ARG + DESC:\n if t.sub!(re_argument,\"\")\n decfirst = 0 unless !decfirst.nil?\n spec = \"\#$1\".expand_tabs!()\n desc = \"\#$2\".expand_tabs!()\n\n while t.gsub!(re_more_desc, '')\n desc += \"\#$1\".expand_tabs!\n end\n\n next if desc =~ /\\[\\s*undocumented\\s*\\]/i\n\n uoff = 0\n spec.gsub!(/(<[a-zA-Z]\\w*):([^>]+)>/e) { |i|\n uoff += 1 + \"\#$2\".length() and \"\#$1>\"\n }\n spec.gsub!(/\\t/,\"=\")\n\n ditto = desc =~ /\\A\\s*\\[ditto\\]/\n desc.gsub!(/^\\s*\\[.*?\\]\\s*\\n/m,\"\")\n desc.gsub!(BracketDirectives,'')\n #desc.gsub!(/\\[.*?\\]/,\"\")\n\n \n if ditto\n desc = (lastdesc ? _ditto(lastflag,lastdesc,desc) : \"\" )\n elsif desc =~ /\\A\\s*\\Z/\n next\n else\n lastdesc = desc\n end\n\n spec =~ /\\A\\s*(\\S+)/ and lastflag = \"\#$1\"\n \n desc.sub!(/\\s+\\Z/, \"\\n\")\n usage += spec + ' ' * uoff + desc\n next\n end\n\n \n\n # OTHERWISE, DECORATION\n if t.sub!(/((?:(?!\\[\\s*pvtype:).)*)(\\n|(?=\\[\\s*pvtype:))/,\"\")\n desc = \"\#$1\"+(\"\#$2\"||'')\n #desc.gsub!(/^(\\s*\\[.*?\\])+\\s*\\n/m,'')\n #desc.gsub!(/\\[.*?\\]/,'') # eliminates anything in brackets\n if @tight || desc !~ /\\A\\s*\\Z/\n desc.gsub!(BracketDirectives,'')\n next if desc =~ /\\A\\s*\\Z/\n end\n decfirst = 1 unless !decfirst.nil? or desc =~ /\\A\\s*\\Z/\n usage += desc\n end\n\n end #while\n\n required = ''\n \n for arg in @args\n required += ' ' + arg.desc + ' ' if arg.required\n end\n \n usage.gsub!(/\\255/,\"[/\") # REINSTATE ESCAPED '['s\n \n required.gsub!(/<([a-zA-Z]\\w*):[^>]+>/,'<\\1>')\n required.rstrip!\n \n helpcmd = Getopt::Declare::Arg::besthelp\n versioncmd = Getopt::Declare::Arg::bestversion\n \n \n header = ''\n unless @source.nil?\n header << version()\n prog = \"\#{$0}\"\n prog.sub!(%r#.*/#,'')\n header << \"Usage: \#{prog} [options]\#{required}\\n\"\n header << \" \#{prog} \#{helpcmd}\\n\" if helpcmd\n header << \" \#{prog} \#{versioncmd}\\n\" if versioncmd\n header << \"\\n\" unless decfirst && decfirst == 1 && usage =~ /\\A[ \\t]*\\n/\n end\n \n header << \"Options:\\n\" unless decfirst && decfirst == 1\n \n usage.sub!(/[\\s\\n]+\\Z/m, '')\n\n pager = $stdout\n\n #begin\n # eval('require \"IO/Pager\";')\n # pager = IO::Pager.new()\n #rescue\n #end\n\n if opt.empty?\n pager.puts \"\#{header}\#{usage}\"\n return 0\n ### usage\n end\n\n #usage.sub!(/\\A[\\s\\n]+/m, '')\n pager.puts \"\#{header}\#{usage}\"\n exit(opt[0]) if opt[0]\n end\n\n attr_accessor :unused\n \n\n # Return list of used parameters (after parsing)\n def used\n used = @cache.keys\n return used.join(' ')\n end\n\n @@m = []\n\n # Main method to generate code to be evaluated for parsing.\n def code(*t)\n package = t[0] || ''\n code = %q%\n\n\n@_deferred = []\n@_errormsg = nil\n@_finished = nil\n\nbegin\n\n begin\n undef :defer\n undef :reject\n undef :finish\n rescue\n end\n\n def defer(&i)\n @_deferred.push( i )\n end\n\n def reject(*i)\n if !i || i[0]\n @_errormsg = i[1] if i[1]\n throw :paramout\n end\n end\n\n def finish(*i)\n if i.size\n @_finished = i\n else\n @_finished = true\n end\n end\n\n @unused = []\n @cache = {}\n _FOUND_ = {}\n _errors = 0\n _invalid = {}\n _lastprefix = nil\n\n _pos = 0 # current position to match from\n _nextpos = 0 # next position to match from\n\n catch(:alldone) do \n while !@_finished\n begin\n catch(:arg) do\n @_errormsg = nil\n\n # This is used for clustering of flags\n while _lastprefix\n substr = _args[_nextpos..-1]\n substr =~ /^(?!\\s|\\0|\\Z)% +\n Getopt::Declare::Arg::negflagpat() + %q%/ or\n begin \n _lastprefix=nil\n break\n end\n \"\#{_lastprefix}\#{substr}\" =~ /^(% +\n Getopt::Declare::Arg::posflagpat() + %q%)/ or\n begin \n _lastprefix=nil\n break\n end\n _args = _args[0.._nextpos-1] + _lastprefix + _args[_nextpos..-1]\n break\n end # while _lastprefix\n\n % + '' + %q%\n _pos = _nextpos if _args\n\n usage(0) if _args && gindex(_args,/\\G(% + @helppat + %q%)(\\s|\\0|\\Z)/,_pos)\n version(0) if _args && _args =~ /\\G(% + @verspat + %q%)(\\s|\\0|\\Z)/\n %\n\n for arg in @args\n code << arg.code(self,package)\n end\n\n code << %q%\n\n if _lastprefix\n _pos = _nextpos + _lastprefix.length()\n _lastprefix = nil\n next\n end\n\n _pos = _nextpos\n\n _args && _pos = gindex( _args, /\\G[\\s|\\0]*(\\S+)/, _pos ) or throw(:alldone)\n\n if @_errormsg\n $stderr.puts( \"Error\#{source}: \#{@_errormsg}\\n\" )\n else\n @unused.push( @@m[0] )\n end\n\n _errors += 1 if @_errormsg\n\n end # catch(:arg)\n\n ensure # begin\n _pos = 0 if _pos.nil?\n _nextpos = _pos if _args\n if _args and _args.index( /\\G(\\s|\\0)*\\Z/, _pos )\n _args = _get_nextline.call(self) if !@_finished\n throw(:alldone) unless _args\n _pos = _nextpos = 0\n _lastprefix = ''\n end # if\n end # begin/ensure\n end # while @_finished\n end # catch(:alldone)\nend # begin\n\n%\n\n\n ################################\n # Check for required arguments #\n ################################\n for arg in @args\n next unless arg.required\n\n code << %q%unless _FOUND_['% + arg.name + %q%'] %\n\n if @mutex[arg.name]\n for m in @mutex[arg.name]\n code << %q# or _FOUND_['# + m + %q#']#\n end\n end\n\n code << %q%\n $stderr.puts \"Error\#{@source}: required parameter '% + arg.name + %q%' not found.\"\n _errors += 1\nend\n%\n\n end\n\n ########################################\n # Check for arguments requiring others #\n ########################################\n\n for arg in @args\n next unless arg.requires\n\n code << %q%\nif _FOUND_['% + arg.name + %q%'] && !(% + arg.found_requires +\n %q%)\n $stderr.puts \"Error\#{@source}: parameter '% + arg.name + %q%' can only be specified with '% + arg.requires + %q%'\"\n _errors += 1\nend\n %\n end\n\n code << %q%\n#################### Add unused arguments\nif _args && _nextpos > 0 && _args.length() > 0\n @unused.replace( @unused + _args[_nextpos..-1].split(' ') )\nend\n\nfor i in @unused\n i.tr!( \"\\0\", \" \" )\nend\n\n%\n\n if @strict\n code << %q%\n#################### Handle strict flag\nunless _nextpos < ( _args ? _args.length : 0 )\n for i in @unused\n $stderr.puts \"Error\#{@source}: unrecognizable argument ('\#{i}')\"\n _errors += 1\n end\nend\n%\n end\n\n code << %q%\n#################### Print help hint\nif _errors > 0 && !@source.nil?\n $stderr.puts \"\\n(try '\#$0 % + Getopt::Declare::Arg::besthelp + %q%' for more information)\"\nend\n\n## cannot just assign unused to ARGV in ruby\nunless @source != ''\n ARGV.clear\n @unused.map { |i| ARGV.push(i) }\nend\n\nunless _errors > 0\n for i in @_deferred\n begin\n i.call\n rescue => e\n STDERR.puts \"Action in Getopt::Declare specification produced:\\n\#{e}\"\n _errors += 1\n end\n end\nend\n\n!(_errors>0) # return true or false (false for errors)\n\n%\n return code\n end\n\n\n # Inspect cache (not the declare object)\n def inspect\n return nil if !@cache \n t = ''\n\n @cache.each { |a,b|\n t << a + \" => \"\n case b\n when Hash\n t << \"{\"\n i = []\n b.each { |c,d|\n i.push( \" '\#{c}' => \" + d.inspect )\n }\n t << i.join(',')\n t << \" }\"\n else\n t << b.inspect\n end\n t << \"\\n\"\n }\n t << \"Unused: \" + unused.join(', ')\n end\n\n # Iterator for Getopt::Declare (travels thru all cache keys)\n def each(&t)\n @cache.each(&t)\n end\n\n # Operator to easily create new value in of Getopt::Declare\n def []=(name,val)\n @cache = {} unless @cache\n @cache[name] = val\n end\n\n # Operator to easily return cache of Getopt::Declare\n def [](name)\n if @cache\n return @cache[name]\n else\n return nil\n end\n end\n\n # Operator to return number of flags set\n def size\n return 0 unless @cache\n return @cache.keys.size\n end\n\n attr :mutex\n attr :helppat\n attr :verspat\n attr :strict\n attr :clump\n attr :source\n\n end # class Declare\n\nend # module Getopt\n"