getopt-declare 1.28 → 1.29

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/Manifest.txt CHANGED
File without changes
data/README.txt CHANGED
File without changes
@@ -0,0 +1,23 @@
1
+ require "rubygems"
2
+
3
+ spec = Gem::Specification.new do |spec|
4
+ spec.name = "getopt-declare"
5
+ spec.version = '1.29'
6
+ spec.author = "Gonzalo Garramuno"
7
+ spec.email = 'ggarra13@gmail.com'
8
+ spec.homepage = 'http://www.rubyforge.org/projects/getoptdeclare/'
9
+ spec.summary = 'A regex command-line parsing library.'
10
+ spec.require_path = "lib"
11
+ spec.files =
12
+ ['getopt-declare.gemspec'] +
13
+ Dir.glob("lib/Getopt/*.rb") +
14
+ Dir.glob("samples/*.rb") + Dir.glob("test/*.rb")
15
+ spec.description = <<-EOF
16
+ Interactive Fiction Mapping Tool.
17
+ EOF
18
+ spec.extra_rdoc_files = ["Manifest.txt", "README.txt"] +
19
+ Dir.glob("docs/*/*")
20
+ spec.has_rdoc = true
21
+ spec.rubyforge_project = 'getopt-declare'
22
+ spec.required_ruby_version = '>= 1.8.0'
23
+ end
@@ -1432,17 +1432,20 @@ EOS
1432
1432
 
1433
1433
  usage.sub!(/[\s\n]+\Z/m, '')
1434
1434
 
1435
- if opt.empty?
1436
- return header + usage + "\n"
1437
- end
1438
-
1439
1435
  pager = $stdout
1436
+
1440
1437
  #begin
1441
1438
  # eval('require "IO/Pager";')
1442
1439
  # pager = IO::Pager.new()
1443
1440
  #rescue
1444
1441
  #end
1445
1442
 
1443
+ if opt.empty?
1444
+ pager.puts "#{header}#{usage}"
1445
+ return 0
1446
+ ### usage
1447
+ end
1448
+
1446
1449
  #usage.sub!(/\A[\s\n]+/m, '')
1447
1450
  pager.puts "#{header}#{usage}"
1448
1451
  exit(opt[0]) if opt[0]
@@ -0,0 +1,1740 @@
1
+ #
2
+ # Getopt::Declare - Declaratively Expressed Command-Line Arguments via Regular Expressions
3
+ #
4
+ # Ruby port of Perl's Getopt::Declare, version 1.21,
5
+ # released May 21, 1999.
6
+ #
7
+ # $Release Version: 1.28 $
8
+ # $Date: 2007/01/15 10:53:09 $
9
+ # by Gonzalo Garramu�o
10
+ #
11
+ # For detailed instructions, see Declare.rdoc file
12
+ #
13
+ # Ruby Port:
14
+ # Copyright (c) 2004, Gonzalo Garramuno. All Rights Reserved.
15
+ # This package is free software. It may be used, redistributed
16
+ # and/or modified under the terms of the Perl Artistic License
17
+ # (see http://www.perl.com/perl/misc/Artistic.html)
18
+ #
19
+ # Original Perl Implementation:
20
+ # Damian Conway (damian@conway.org)
21
+ # Copyright (c) 1997-2000, Damian Conway. All Rights Reserved.
22
+ # This package is free software. It may be used, redistributed
23
+ # and/or modified under the terms of the Perl Artistic License
24
+ # (see http://www.perl.com/perl/misc/Artistic.html)
25
+ #
26
+
27
+ require "Getopt/DelimScanner"
28
+
29
+
30
+ # Verifies that code is valid Ruby code. returns false if not
31
+ def valid_syntax?(code, fname = 'parser_code')
32
+ eval("BEGIN {return true}\n#{code}", nil, fname, 0)
33
+ rescue Exception
34
+ false
35
+ end
36
+
37
+
38
+ # An add-on to the String class
39
+ class String
40
+ # Expand all tabs to spaces
41
+ def expand_tabs!( tabstop = 8 )
42
+ while self.sub!(/(^|\n)([^\t\n]*)(\t+)/sex) { |f|
43
+ val = ( tabstop * "#$3".length() - ("#$2".length() % tabstop) )
44
+ "#$1#$2" + (" " * val)
45
+ }
46
+ end
47
+ self
48
+ end
49
+
50
+ # Return new string with all tabs set to spaces
51
+ def expand_tabs( tabstop = 8 )
52
+ h = self.dup
53
+ while h.sub!(/(^|\n)([^\t\n]*)(\t+)/sex) { |f|
54
+ val = ( tabstop * "#$3".length() - ("#$2".length() % tabstop) )
55
+ "#$1#$2" + (" " * val)
56
+ }
57
+ end
58
+ h
59
+ end
60
+ end
61
+
62
+
63
+ # Regex for removing bracket directives
64
+ BracketDirectives =
65
+ /\[\s*(?:ditto|tight|strict|no\s*case|repeatable|debug|required|mutex:.*|implies:.*|excludes:.*|requires:.*|cluster:.*)\s*\]/
66
+
67
+
68
+ module Getopt
69
+
70
+ # Main Class
71
+ class Declare
72
+
73
+ VERSION = '1.28'
74
+
75
+ # For debugging, use [debug] and it will output the ruby code as .CODE.rb
76
+ @@debug = false
77
+
78
+ # Main separator used to distinguish arguments in Getopt/Declare spec.
79
+ # By default, one or more tabs or 3 spaces or more.
80
+ @@separator = '(?:\t+| {3}[^<])'
81
+
82
+ # Class used to handle the beginning of options
83
+ class StartOpt
84
+
85
+ # Returns regex used matching start of options
86
+ def matcher(g)
87
+ '(?:()'
88
+ end
89
+
90
+ # Returns code used
91
+ def code(*t)
92
+ ''
93
+ end
94
+
95
+ # Returns how to cache code in class
96
+ def cachecode(a,b)
97
+ ''
98
+ end
99
+
100
+ # Helps build regex that matches parameters of flags
101
+ def trailer
102
+ nil
103
+ end
104
+
105
+ # Helps build regex that matches parameters of flags
106
+ def ows(g)
107
+ g
108
+ end
109
+ end # StartOpt
110
+
111
+
112
+ # Class used to handle the ending of options
113
+ class EndOpt < StartOpt
114
+ # Returns regex used matching end of options
115
+ def matcher(g)
116
+ '())?'
117
+ end
118
+ end # EndOpt
119
+
120
+
121
+ # Class used to handle scalar (ie.non-array) parameters
122
+ class ScalarArg
123
+
124
+ @@stdtype = {}
125
+
126
+ # (re)set standard types
127
+ def ScalarArg._reset_stdtype
128
+ @@stdtype = {
129
+ ':i' => { :pattern => '(?:(?:%T[+-]?)%D+)' },
130
+ ':n' => { :pattern => '(?:(?:%T[+-]?)(?:%D+(?:%T\.%D*)?' +
131
+ '(?:%T[eE](?:[+-])?%D+)?|%T\.%D+(?:%T[eE](?:[+-])?%D+)?))',
132
+ },
133
+ ':s' => { :pattern => '(?:%T(?:\S|\0))+(?=\s|\0|\z)' },
134
+ ':qs' => { :pattern => %q{"(?:\\"|[^"])*"|'(?:\\'|[^'])*'|(?:%T(?:\S|\0))+} },
135
+ ':id' => { :pattern => '%T[a-zA-Z_](?:%T\w)*(?=\s|\0|\z)' },
136
+ ':d' => {
137
+ :pattern => '(?:%T(?:\S|\0))+',
138
+ :action => %q%
139
+ reject( (_VAL_.nil? || !test(?d, _VAL_) ),
140
+ "in parameter '#{_PARAM_}' (\"#{_VAL_}\" is not a directory)")%
141
+ },
142
+ ':if' => {
143
+ :pattern => '%F(?:%T(?:\S|\0))+(?=\s|\0|\z)',
144
+ :action => %q%
145
+ reject( (_VAL_.nil? || _VAL_ != "-" && !test(?r, _VAL_) ),
146
+ "in parameter '#{_PARAM_}' (file \"#{_VAL_}\" is not readable)")%
147
+ },
148
+ ':of' => {
149
+ :pattern => '%F(?:%T(?:\S|\0))+(?=\s|\0|\z)',
150
+ :action => %q%
151
+ reject( (_VAL_.nil? || _VAL_ != "-" &&
152
+ test(?r, _VAL_) && !test(?w, _VAL_)),
153
+ "in parameter '#{_PARAM_}' (file \"#{_VAL_}\" is not writable)")%
154
+ },
155
+ '' => { :pattern => ':s', :ind => 1 },
156
+
157
+ ':+i' => {
158
+ :pattern => ':i',
159
+ :action => %q%reject( _VAL_ <= 0,
160
+ "in parameter '#{_PARAM_}' (#{_VAL_} must be an integer greater than zero)")%,
161
+ :ind => 1
162
+ },
163
+ ':+n' => {
164
+ :pattern => ':n',
165
+ :action => %q%reject( _VAL_ <= 0.0,
166
+ "in parameter '#{_PARAM_}' (#{_VAL_} must be a number greater than zero)")%,
167
+ :ind => 1
168
+ },
169
+ ':0+i' => {
170
+ :pattern => ':i',
171
+ :action => %q%reject( _VAL_ < 0,
172
+ "in parameter '#{_PARAM_}' (#{_VAL_} must be an positive integer)")%,
173
+ :ind => 1
174
+ },
175
+ ':0+n' => {
176
+ :pattern => ':n',
177
+ :action => %q%reject( _VAL_ < 0,
178
+ "in parameter '#{_PARAM_}' (#{_VAL_} must be an positive number)")%,
179
+ :ind => 1
180
+ },
181
+ }
182
+
183
+ end # _reset_stdtype
184
+
185
+
186
+ # Given a standard type name, return the corresponding regex
187
+ # pattern or nil
188
+ def ScalarArg.stdtype(name)
189
+ seen = {}
190
+ while (!seen[name] && @@stdtype[name] && @@stdtype[name][:ind])
191
+ seen[name] = 1; name = @@stdtype[name][:pattern]
192
+ end
193
+
194
+ return nil if seen[name] || !@@stdtype[name]
195
+ @@stdtype[name][:pattern]
196
+ end
197
+
198
+ def stdtype(name)
199
+ ScalarArg.stdtype(name)
200
+ end
201
+
202
+
203
+ # Given the name of a type, return its corresponding action(s)
204
+ def ScalarArg.stdactions(name)
205
+ seen = {}
206
+ actions = []
207
+ while (!seen[name] && @@stdtype[name] && @@stdtype[name][:ind])
208
+ seen[name] = 1
209
+ if @@stdtype[name][:action]
210
+ actions.push( @@stdtype[name][:action] )
211
+ end
212
+ name = @@stdtype[name][:pattern]
213
+ end
214
+
215
+ if @@stdtype[name] && @@stdtype[name][:action]
216
+ actions.push( @@stdtype[name][:action] )
217
+ end
218
+
219
+ return actions
220
+ end
221
+
222
+ # Add a new (user defined) type to the standard types
223
+ def ScalarArg.addtype(abbrev, pattern, action, ref)
224
+
225
+ typeid = ":#{abbrev}"
226
+ unless (pattern =~ /\S/)
227
+ pattern = ":s"
228
+ ref = 1
229
+ end
230
+
231
+ @@stdtype[typeid] = {}
232
+ @@stdtype[typeid][:pattern] = "(?:#{pattern})" if pattern && !ref
233
+ @@stdtype[typeid][:pattern] = ":#{pattern}" if pattern && ref
234
+ @@stdtype[typeid][:action] = action if action
235
+ @@stdtype[typeid][:ind] = ref
236
+
237
+ end
238
+
239
+ attr :name
240
+ attr :type
241
+ attr :nows
242
+
243
+
244
+ # Constructor
245
+ def initialize(name, type, nows)
246
+ @name = name
247
+ @type = type
248
+ @nows = nows
249
+ end
250
+
251
+ # Create regexp to match parameter
252
+ def matcher(g)
253
+ trailing = g ? '(?!'+Regexp::quote(g)+')' : ''
254
+
255
+ # Find type in list of standard (and user) types
256
+ stdtype = stdtype(@type)
257
+
258
+ # Handle stdtypes that are specified as regex in parameter
259
+ if (!stdtype && @type =~ %r"\A:/([^/]+)/\Z" )
260
+ stdtype = "#$1"
261
+ end
262
+
263
+ if stdtype.nil?
264
+ raise "Error: bad type in Getopt::Declare parameter variable specification near '<#{@name}#{@type}>'\nValid types are:\n" + @@stdtype.keys.inspect
265
+ end
266
+
267
+ stdtype = stdtype.dup # make a copy, as we'll change it in place
268
+ stdtype.gsub!(/\%D/,"(?:#{trailing}\\d)")
269
+ stdtype.gsub!(/\%T/,trailing)
270
+ unless ( stdtype.sub!("\%F","") )
271
+ stdtype = Getopt::Declare::Arg::negflagpat + stdtype
272
+ end
273
+ return "(?:#{stdtype})"
274
+ end
275
+
276
+ # Return string with code to process parameter
277
+ def code(*t)
278
+ if t[0]
279
+ pos1 = t[0].to_s
280
+ else
281
+ pos1 = '0'
282
+ end
283
+
284
+ c = conversion
285
+ c = "\n _VAL_ = _VAL_#{c} if _VAL_" if c
286
+
287
+ code = <<-EOS
288
+ _VAR_ = %q|<#{@name}>|
289
+ _VAL_ = @@m[#{pos1}]
290
+ _VAL_.tr!("\\0"," ") if _VAL_#{c}
291
+ EOS
292
+
293
+ actions = Getopt::Declare::ScalarArg::stdactions(@type)
294
+
295
+ for i in actions
296
+ next if i.nil?
297
+ # i.sub!(/(\s*\{)/, '\1 module '+t[1])
298
+ code << "
299
+ begin
300
+ #{i}
301
+ end
302
+ "
303
+ end
304
+
305
+ code << " #{@name} = _VAL_\n"
306
+ end
307
+
308
+ # Based on parameter type, default conversion to apply
309
+ def conversion
310
+ pat = @@stdtype[@type] ? @@stdtype[@type][:pattern] : ''
311
+ [ @type, pat ].each { |t|
312
+ case t
313
+ when /^\:0?(\+)?i$/
314
+ return '.to_i'
315
+ when /^\:0?(\+)?n$/
316
+ return '.to_f'
317
+ end
318
+ }
319
+ return nil
320
+ end
321
+
322
+ # Return string with code to cache argument in Getopt::Declare's cache
323
+ def cachecode(ownerflag, itemcount)
324
+ if itemcount > 1
325
+ " @cache['#{ownerflag}']['<#{@name}>'] = #{@name}\n"
326
+ else
327
+ " @cache['#{ownerflag}'] = #{@name}\n"
328
+ end
329
+ end
330
+
331
+ # Helps build regex that matches parameters of flags
332
+ def trailer
333
+ nil # MEANS TRAILING PARAMETER VARIABLE (in Perl,was '')
334
+ end
335
+
336
+ # Helps build regex that matches parameters of flags
337
+ # Wraps parameter passed for #$1, etc. matching
338
+ def ows(g)
339
+ return '[\s|\0]*(' + g + ')' unless @nows
340
+ '('+ g +')'
341
+ end
342
+
343
+ end # ScalarArg
344
+
345
+
346
+ # Class used to handle array arguments
347
+ class ArrayArg < ScalarArg
348
+
349
+ # Create regexp to match array
350
+ def matcher(g)
351
+ suffix = !g.nil? ? '([\s\0]+)' : ''
352
+ scalar = super # contains regex to match a scalar element
353
+ # we match one obligatory element, and one or more optionals ')*'
354
+ return scalar + '(?:[\s\0]+' + scalar + ')*' + suffix
355
+ end
356
+
357
+ # Return string with code to process array parameter
358
+ def code(*t)
359
+
360
+ if t[0]
361
+ pos1 = t[0].to_s
362
+ else
363
+ pos1 = '0'
364
+ end
365
+
366
+ code = <<-EOS
367
+ _VAR_ = %q|<#{@name}>|
368
+ _VAL_ = nil
369
+ #{@name} = (@@m[#{pos1}]||'').split(' ').map { |i|
370
+ i.tr("\\0", " ") }
371
+ EOS
372
+
373
+ # Handle conversion to proper type
374
+ c = conversion
375
+ if c
376
+ code << " #{@name}.map! { |i| i#{c} }\n"
377
+ end
378
+
379
+ actions = Getopt::Declare::ScalarArg::stdactions(@type)
380
+ if actions.size > 0
381
+ code << " for _VAL_ in #{@name}\n"
382
+ for i in actions
383
+ code << " #{i}\n"
384
+ end
385
+ code << " end\n\n"
386
+ end
387
+ return code
388
+ end
389
+
390
+ # Return string with code to cache array in Getopt::Declare's cache
391
+ def cachecode(ownerflag, itemcount)
392
+ if itemcount > 1
393
+ " @cache['#{ownerflag}']['<#{@name}>'] = [] unless @cache['#{ownerflag}']['<#{@name}>']
394
+ @cache['#{ownerflag}']['<#{@name}>'] = #{@name}\n"
395
+ else
396
+ " @cache['#{ownerflag}'] = #{@name}\n"
397
+ end
398
+ end
399
+
400
+ end # ArrayArg
401
+
402
+
403
+ # Class used to handle punctuations (., -, etc.)
404
+ class Punctuator
405
+
406
+ # Constructor
407
+ def initialize(text, nows)
408
+ @text = text
409
+ @nows = nows
410
+ end
411
+
412
+ # Return regex that matches this punctuation
413
+ def matcher(g)
414
+ Arg::negflagpat + Regexp::quote(@text)
415
+ end
416
+
417
+ # Return string with code to process punctuation
418
+ def code(*t)
419
+
420
+ if t[0]
421
+ pos1 = t[0].to_s
422
+ else
423
+ pos1 = '0'
424
+ end
425
+ " if @@m[#{pos1}] && !@@m[#{pos1}].empty?
426
+ _PUNCT_['#{@text}'] = @@m[#{pos1}]
427
+ end
428
+ "
429
+ end
430
+
431
+ # Return string with code to cache punctuation in Getopt::Declare's cache
432
+ def cachecode(ownerflag, itemcount)
433
+ if itemcount > 1
434
+ " @cache['#{ownerflag}']['#{@text}'] = _PUNCT_['#{@text}']\n"
435
+ else
436
+ " unless @cache['#{ownerflag}']\n" +
437
+ " @cache['#{ownerflag}'] = _PUNCT_['#{@text}'] || 1\n" +
438
+ " end\n"
439
+ end
440
+ end
441
+
442
+ # Helps build regex that matches parameters of flags
443
+ def trailer
444
+ @text
445
+ end
446
+
447
+ # Helps build regex that matches parameters of flags
448
+ # Wraps parameter passed for #$1, etc. matching
449
+ def ows(g)
450
+ return '[\s\0]*(' + g + ')' unless @nows
451
+ '(' + g + ')'
452
+ end #ows
453
+
454
+ end # Punctuator
455
+
456
+
457
+ # Class used to handle other arguments (flags, etc)
458
+ class Arg
459
+
460
+ @@nextid = 0
461
+
462
+
463
+ Helpcmd = %w( -help --help -Help --Help -HELP --HELP -h -H )
464
+
465
+ @@helpcmdH = {}
466
+ for i in Helpcmd; @@helpcmdH[i] = 1; end
467
+
468
+ def Arg.besthelp
469
+ for i in Helpcmd; return i if @@helpcmdH[i]; end
470
+ end
471
+
472
+ # Create regex of help flags based on help shortcuts left
473
+ def Arg.helppat
474
+ @@helpcmdH.keys.join('|')
475
+ end
476
+
477
+
478
+ Versioncmd = %w( -version --version -Version --Version
479
+ -VERSION --VERSION -v -V )
480
+ @@versioncmdH = {}
481
+ for i in Versioncmd; @@versioncmdH[i] = 1; end
482
+
483
+ def Arg.bestversion
484
+ for i in Versioncmd; return i if @@versioncmdH[i]; end
485
+ end
486
+
487
+ # Create regex of version flags based on help shortcuts left
488
+ def Arg.versionpat
489
+ @@versioncmdH.keys.join('|')
490
+ end
491
+
492
+ @@flags = []
493
+ @@posflagpat = nil
494
+ @@negflagpat = nil
495
+
496
+ def Arg.clear
497
+ @@flags = []
498
+ @@nextid = 0
499
+ @@posflagpat = nil
500
+ @@negflagpath = nil
501
+ end
502
+
503
+ # Return string with regex that avoids all flags in declaration
504
+ def Arg.negflagpat(*t)
505
+ if !@@negflagpat && @@flags
506
+ @@negflagpat = ( @@flags.map { |i|
507
+ "(?!" + Regexp::quote(i) + ")" } ).join('')
508
+ else
509
+ @@negflagpat
510
+ end
511
+ end
512
+
513
+ # Return string with regex that matches any of the flags in declaration
514
+ def Arg.posflagpat(*t)
515
+ if !@@posflagpat && @@flags
516
+ @@posflagpat = '(?:' + ( @@flags.map { |i|
517
+ Regexp::quote(i) } ).join('|') + ')'
518
+ else
519
+ @@posflagpat
520
+ end
521
+ end
522
+
523
+ attr_accessor :flag, :args, :actions, :ditto, :nocase
524
+ attr_accessor :required, :id, :repeatable, :desc
525
+ attr_accessor :requires
526
+
527
+
528
+ #
529
+ def found_requires
530
+ expr = @requires.gsub(/((?:&&|\|\|)?\s*(?:[!(]\s*)*)([^ \t\n|&\)]+)/x,
531
+ '\1_FOUND_[\'\2\']')
532
+
533
+ if !valid_syntax?( expr )
534
+ raise "Error: bad condition in [requires: #{original}]\n"
535
+ end
536
+ expr
537
+ end
538
+
539
+
540
+ # Constructor
541
+ def initialize(spec, desc, dittoflag)
542
+ first = 1
543
+
544
+
545
+ @@nextid += 1
546
+ @flag = ''
547
+ @foundid = nil
548
+ @args = []
549
+ @actions = []
550
+ @ditto = dittoflag
551
+ @required = false
552
+ @requires = nil
553
+ @id = @@nextid
554
+ @desc = spec.dup
555
+ @items = 0
556
+ @nocase = false
557
+
558
+ @desc.sub!(/\A\s*(.*?)\s*\Z/,'\1')
559
+
560
+ while spec && spec != ''
561
+ begin
562
+
563
+ # OPTIONAL
564
+ if spec.sub!( /\A(\s*)\[/, '\1' )
565
+ @args.push( StartOpt.new )
566
+ next
567
+ elsif spec.sub!(/\A\s*\]/,"")
568
+ @args.push( EndOpt.new )
569
+ next
570
+ end
571
+
572
+ # ARG
573
+
574
+ se = DelimScanner::new( spec )
575
+ tmp = se.scanBracketed('<>')
576
+
577
+ arg = nows = nil
578
+ arg, spec, nows = tmp[:match], tmp[:suffix], tmp[:prefix] if tmp
579
+
580
+
581
+ if arg
582
+ arg =~ /\A(\s*)(<)([a-zA-Z]\w*)(:[^>]+|)>/ or
583
+ raise "Error: bad Getopt::Declare parameter variable specification near '#{arg}'\n"
584
+
585
+ # NAME,TYPE,NOW
586
+ details = [ "#$3", "#$4", !first && !(nows.length>0) ]
587
+
588
+ if spec && spec.sub!( /\A\.\.\./, "") # ARRAY ARG
589
+ @args.push( ArrayArg.new(*details) )
590
+ else # SCALAR ARG
591
+ @args.push( ScalarArg.new(*details) )
592
+ end
593
+ @items += 1
594
+ next
595
+
596
+ # PUNCTUATION
597
+ elsif spec.sub!( /\A(\s*)((\\.|[^\] \t\n\[<])+)/, '' )
598
+ ows, punct = $1, $2
599
+ punct.gsub!( /\\(?!\\)(.)/, '\1' )
600
+
601
+ if first
602
+ spec =~ /\A(\S+)/
603
+ @foundid = "#{punct}#{$1}"
604
+ @flag = punct
605
+ @@flags.push( punct )
606
+ else
607
+ @args.push( Punctuator.new(punct, !(ows.size > 0)) )
608
+ @items += 1
609
+ end
610
+
611
+ else
612
+ break
613
+ end # if arg/spec.sub
614
+ ensure
615
+ first = nil
616
+ end
617
+ end # while
618
+
619
+ @@helpcmdH.delete(@flag) if @@helpcmdH.key?(@flag)
620
+ @@versioncmdH.delete(@flag) if @@versioncmdH.key?(@flag)
621
+ end # initialize
622
+
623
+
624
+
625
+ # Return String with code to parse this argument (ie. flag)
626
+ def code(*t)
627
+ owner = t[0]
628
+ mod = t[1]
629
+
630
+
631
+ code = "\n"
632
+ flag = @flag
633
+ clump = owner.clump
634
+ i = 0
635
+ nocasei = ((Getopt::Declare::nocase || @nocase) ? 'i' : '')
636
+
637
+ code << " catch(:paramout) do\n while "
638
+ code += !@repeatable? "!_FOUND_['" + self.foundid + "']" : "true"
639
+
640
+ if (flag && (clump==1 && flag !~ /\A[^a-z0-9]+[a-z0-9]\Z/i ||
641
+ (clump<3 && @args.size > 0 )))
642
+ code << ' and !_lastprefix'
643
+ end
644
+
645
+ code <<'
646
+ begin
647
+ catch(:param) do
648
+ _pos = _nextpos if _args
649
+ _PUNCT_ = {}
650
+ '
651
+
652
+ if flag != ''
653
+ # This boundary is to handle -- option, so that if user uses
654
+ # --foo and --foo is not a flag, it does not become
655
+ # -- and unused: 'foo', but an error saying flag '--foo' not defined.
656
+ boundary = ''
657
+ boundary = '(\s+|\Z)' if flag =~ /^(--|-|\+|\+\+)$/
658
+
659
+ code << '
660
+ _args && _pos = gindex( _args, /\G[\s|\0]*' +
661
+ Regexp::quote(flag) + boundary + '/' + nocasei + ", _pos) or throw(:paramout)
662
+ unless @_errormsg
663
+ @_errormsg = %q|incorrect specification of '" + flag + "' parameter|
664
+ end
665
+ "
666
+ elsif ( ScalarArg::stdtype(@args[0].type)||'') !~ /\%F/
667
+ code << "\n throw(:paramout) if @_errormsg\n"
668
+ end
669
+
670
+
671
+ code << "\n _PARAM_ = '" + self.name + "'\n"
672
+
673
+
674
+ trailer = []
675
+ i = @args.size-1
676
+ while i > 0
677
+ trailer[i-1] = @args[i].trailer
678
+ trailer[i-1] = trailer[i] unless trailer[i-1]
679
+ i -= 1
680
+ end # while i
681
+
682
+ if @args
683
+ code << "\n"+' _args && _pos = gindex( _args, /\G'
684
+
685
+ @args.each_with_index { |arg, i|
686
+ code << arg.ows(arg.matcher(trailer[i]))
687
+ }
688
+
689
+ code << '/x' + nocasei + ", _pos ) or throw(:paramout)\n"
690
+ end # if @args
691
+
692
+ @args.each_with_index { |arg, i|
693
+ code << arg.code(i,mod) #, $flag ????
694
+ }
695
+
696
+ if flag
697
+ mutexlist = owner.mutex[flag] ?
698
+ ( owner.mutex[flag].map {|i| "'#{i}'"} ).join(',') : ''
699
+
700
+ code << "
701
+ if _invalid.has_key?('#{flag}')
702
+ @_errormsg = %q|parameter '#{flag}' not allowed with parameter '| + _invalid['#{flag}'] + %q|'|
703
+ throw(:paramout)
704
+ else
705
+ for i in [#{mutexlist}]
706
+ _invalid[i] = '#{flag}'
707
+ end
708
+ end #if/then
709
+
710
+ "
711
+ end
712
+
713
+
714
+
715
+ for action in @actions
716
+ #action.sub!( /(\s*\{)/, '\1 module '+mod ) # @TODO
717
+ code << "\n " + action + "\n"
718
+ end
719
+
720
+ if flag && @items==0
721
+ code << "\n @cache['#{flag}'] = '#{flag}'\n"
722
+ if @ditto
723
+ code << "\n @cache['#{@ditto.flag}'] = '#{flag}'\n"
724
+ end
725
+ end
726
+
727
+ if @items > 1
728
+ code << " @cache['#{self.name}'] = {} unless @cache['#{self.name}'].kind_of?(Hash)\n"
729
+ if @ditto
730
+ code << "\n @cache['#{@ditto.name}'] = {} unless @cache['#{@ditto.name}'].kind_of?(Hash)\n"
731
+ end
732
+ end
733
+
734
+ for subarg in @args
735
+ code << subarg.cachecode(self.name,@items)
736
+ if ditto
737
+ code << subarg.cachecode(@ditto.name,@items)
738
+ end
739
+ end
740
+
741
+ if flag =~ /\A([^a-z0-9]+)/i
742
+ code << ' _lastprefix = "'+ Regexp::quote("#$1") + '"' + "\n"
743
+ else
744
+ code << " _lastprefix = nil\n"
745
+ end
746
+
747
+ code << "
748
+ _FOUND_['"+ self.foundid + "'] = 1
749
+ throw :arg if _pos > 0
750
+ _nextpos = _args.size
751
+ throw :alldone
752
+ end # catch(:param)
753
+ end # begin
754
+ end # while
755
+ end # catch(:paramout)
756
+ "
757
+
758
+ code
759
+ end
760
+
761
+ # Return name of argument, which can be flag's name or variable's name
762
+ def name
763
+ return @flag unless @flag.empty?
764
+ for i in @args
765
+ return "<#{i.name}>" if i.respond_to?(:name)
766
+ end
767
+ raise "Unknown flag name for parameter #{self.desc}"
768
+ end
769
+
770
+ # Return foundid of argument, which can be flag's name or variable's name
771
+ def foundid
772
+ return @foundid || self.name
773
+ end
774
+
775
+ end # Arg
776
+
777
+
778
+ private
779
+
780
+ class << self
781
+ @nocase = false
782
+ attr_accessor :nocase
783
+ end
784
+
785
+ #
786
+ # This is an additional function added to the class to simulate Perl's
787
+ # pos() \G behavior and m///g
788
+ #
789
+ # It performs a regex match, and returns the last index position of the
790
+ # match or nil. On successive invocations, it allows doing regex matches
791
+ # NOT from the beginning of the string easily.
792
+ #
793
+ # Class Array @@m stores the list of matches, as #$1 and similar
794
+ # variables have short lifespan in ruby, unlike perl.
795
+ #
796
+ def gindex(str, re, pos)
797
+ @@m.clear()
798
+ if pos = str.index( re, pos )
799
+ l = $&.size # length of match
800
+ if l > 0
801
+ @@m[0] = "#$1"
802
+ @@m[1] = "#$2"
803
+ @@m[2] = "#$3"
804
+ @@m[3] = "#$4"
805
+ @@m[4] = "#$5"
806
+ @@m[5] = "#$6"
807
+ @@m[6] = "#$7"
808
+ @@m[7] = "#$8"
809
+ @@m[8] = "#$9"
810
+ pos += l
811
+ end
812
+ end
813
+ pos
814
+ end
815
+
816
+ # Given an array or hash, flatten them to a string
817
+ def flatten(val, nested = nil)
818
+ case val
819
+ when Array
820
+ return val.map{ |i| flatten(i,1) }.join(" ")
821
+ when Hash
822
+ return val.keys.map{ |i| nested ||
823
+ i =~ /^-/ ? [i, flatten(val[i],1)] :
824
+ [flatten(val[i],1)] }.join(" ")
825
+ else
826
+ return val
827
+ end
828
+ end
829
+
830
+ # Read the next line from stdin
831
+ def _get_nextline
832
+ $stdin.readline
833
+ end
834
+
835
+ # For each file provided and found, read it in
836
+ def _load_sources( _get_nextline, files )
837
+ text = ''
838
+ found = []
839
+
840
+ for i in files
841
+ begin
842
+ f = File.open(i,"r")
843
+ rescue
844
+ next
845
+ end
846
+
847
+ if f.tty?
848
+ found.push( '<STDIN>' )
849
+ _get_nextline = method(:_get_nextline)
850
+ else
851
+ found.push( i );
852
+ t = f.readlines.join(' ')
853
+ t.tr!('\t\n',' ')
854
+ text += t
855
+ end
856
+ end
857
+
858
+ return nil unless found.size > 0
859
+ text = $stdin.readline if text.empty?
860
+ return [text, found.join(' or ')]
861
+ end
862
+
863
+
864
+ # Check parameter description for special options
865
+ def _infer(desc, arg, mutex)
866
+ while desc.sub!(/\[\s*mutex:\s*(.*?)\]/i,"")
867
+ _mutex(mutex, "#$1".split(' '))
868
+ end
869
+
870
+ if desc =~ /\[\s*no\s*case\s*\]/i
871
+ if arg
872
+ arg.nocase = true
873
+ else
874
+ nocase = true
875
+ end
876
+ end
877
+
878
+ if !arg.nil?
879
+ if desc =~ /.*\[\s*excludes:\s*(.*?)\]/i
880
+ _exclude(mutex, arg.name, ("#$1".split(' ')))
881
+ end
882
+
883
+ if desc =~ /.*\[\s*requires:\s*(.*?)\s*\]/i
884
+ arg.requires = "#$1"
885
+ end
886
+
887
+ arg.required = ( desc =~ /\[\s*required\s*\]/i )
888
+
889
+ arg.repeatable = ( desc =~ /\[\s*repeatable\s*\]/i )
890
+ end
891
+
892
+ _typedef(desc) while desc.sub!(/.*?\[\s*pvtype:\s*/,"")
893
+
894
+ end
895
+
896
+
897
+
898
+ # Extract a new type from the description and add it to the list
899
+ # of standard types
900
+ def _typedef(desc)
901
+ se = DelimScanner::new( desc )
902
+ tmp = se.scanQuotelike
903
+
904
+ name = nil
905
+ name, desc = tmp[:delimText], tmp[:suffix] if tmp
906
+
907
+ unless name
908
+ desc.sub!(/\A\s*([^\] \t\n]+)/,"") and name = "#$1"
909
+ end
910
+
911
+ raise "Error: bad type directive (missing type name): [pvtype: " +
912
+ desc[0,desc.index(']')||20] + "....\n" unless name
913
+
914
+ se = DelimScanner::new( desc )
915
+ tmp = se.scanQuotelike('\s*:?\s*')
916
+
917
+ # @TODO What is element 2 of extract_quotelike? :trail is a fake here
918
+ # pat,desc,ind = (extract_quotelike(desc,'\s*:?\s*'))[5,1,2]
919
+ pat = ind = nil
920
+ pat, desc, ind = tmp[:match], tmp[:suffix], tmp[:prefix] if tmp
921
+ pat = pat[1..-2] if pat
922
+
923
+ unless pat
924
+ desc.sub!(/\A\s*(:?)\s*([^\] \t\n]+)/,"") and pat = "#$2" and ind = "#$1"
925
+ end
926
+
927
+ pat = '' unless pat
928
+
929
+
930
+ se = DelimScanner::new( desc )
931
+ action = se.extractCodeblock || ''
932
+
933
+ desc.sub!( Regexp::quote(action).to_re, '' )
934
+ action = action[1..-2]
935
+
936
+ raise "Error: bad type directive (expected closing ']' but found " +
937
+ "'#$1' instead): [pvtype: #{name} " + (pat ? "/#{pat}/" : '') +
938
+ " action:#{action} #$1#$2....\n" if desc =~ /\A\s*([^\] \t\n])(\S*)/
939
+
940
+
941
+ Getopt::Declare::ScalarArg::addtype(name,pat,action,ind=~/:/)
942
+ end
943
+
944
+ # Handle quote replacements for [ditto] flag
945
+ def _ditto(originalflag, originaldesc, extra)
946
+ if originaldesc =~ /\n.*\n/
947
+ originaldesc = "Same as #{originalflag} "
948
+ else
949
+ originaldesc.chomp
950
+ originaldesc.gsub!(/\S/,'"')
951
+ while originaldesc.gsub!(/"("+)"/,' \1 ')
952
+ end
953
+ originaldesc.gsub!(/""/,'" ')
954
+ end
955
+
956
+ "#{originaldesc}#{extra}\n"
957
+ end
958
+
959
+ # Check mutex conditions
960
+ def _mutex(mref, mutexlist)
961
+ for flag in mutexlist
962
+ mref[flag] = [] unless mref[flag]
963
+ for otherflag in mutexlist
964
+ next if flag == otherflag
965
+ mref[flag].push( otherflag )
966
+ end
967
+ end
968
+ end
969
+
970
+ # Check exclude conditions
971
+ def _exclude(mref, excluded, mutexlist)
972
+ for flag in mutexlist
973
+ unless flag == excluded
974
+ mref[flag] = [] unless mref[flag]
975
+ mref[excluded] = [] unless mref[excluded]
976
+ mref[excluded].push( flag )
977
+ mref[flag].push( excluded )
978
+ end
979
+ end
980
+ end
981
+
982
+ # Returns a regex to match a single argument line
983
+ def re_argument
984
+ /\A(.*?\S.*?#{@@separator})(.*?\n)/
985
+ end
986
+
987
+ # Returns a regex to keep matching a multi-line description
988
+ # for an argument.
989
+ def re_more_desc
990
+ /\A((?![ \t]*(\{|\n)|.*?\S.*?#{@@separator}.*?\S).*?\S.*\n)/
991
+ end
992
+
993
+ public
994
+
995
+ # Constructor
996
+ def initialize(*opts)
997
+ @cache = nil
998
+
999
+ Getopt::Declare::Arg::clear
1000
+
1001
+ # HANDLE SHORT-CIRCUITS
1002
+ return if opts.size==2 && (!opts[1] || opts[1] == '-SKIP')
1003
+
1004
+ grammar, source = opts
1005
+
1006
+ if grammar.nil?
1007
+ raise "Error: No grammar description provided."
1008
+ end
1009
+
1010
+ ### REMOVED PREDEF GRAMMAR AS IT WAS NOT DOCUMENTED NOR
1011
+ ### WORKING IN PERL'S Declare.pm VERSION.
1012
+
1013
+ # PRESERVE ESCAPED '['s
1014
+ re1 = Regexp.new( Regexp.quote('[/'), nil, 'n')
1015
+ grammar.gsub!( re1,"\255")
1016
+ # grammar.gsub!(/\\\[/,"\255")
1017
+
1018
+ # MAKE SURE GRAMMAR ENDS WITH A NEWLINE.
1019
+ grammar.sub!(/([^\n])\Z/,'\1'+"\n")
1020
+
1021
+ @usage = grammar.dup
1022
+
1023
+ # SET-UP
1024
+ i = grammar
1025
+ _args = []
1026
+ _mutex = {}
1027
+ _strict = false
1028
+ _all_repeatable = false
1029
+ _lastdesc = nil
1030
+ arg = nil
1031
+ Getopt::Declare::nocase = false
1032
+ Getopt::Declare::ScalarArg::_reset_stdtype
1033
+
1034
+
1035
+ # CONSTRUCT GRAMMAR
1036
+ while i.length > 0
1037
+
1038
+ # COMMENT:
1039
+ i.sub!(/\A[ \t]*#.*\n/,"") and next
1040
+
1041
+
1042
+ # TYPE DIRECTIVE:
1043
+ se = DelimScanner::new( i )
1044
+
1045
+ if i =~ /\A\s*\[\s*pvtype:/
1046
+ _action = se.extractBracketed("[")
1047
+ if _action
1048
+ i.sub!( Regexp::quote( _action ).to_re, "" ) ### @GGA: added
1049
+ i.sub!(/\A[ \t]*\n/,"") ### @GGA: added
1050
+ _action.sub!(/.*?\[\s*pvtype:\s*/,"")
1051
+ _typedef(_action)
1052
+ next
1053
+ end # if
1054
+ end
1055
+
1056
+ # ACTION
1057
+ codeblockDelimiters = {
1058
+ '{' => '}',
1059
+ }
1060
+
1061
+ _action = se.extractCodeblock(codeblockDelimiters)
1062
+ if _action
1063
+ i.sub!( Regexp::quote(_action ).to_re, "" )
1064
+ i.sub!(/\A[ \t]*\n/,"")
1065
+ _action = _action[1..-2]
1066
+
1067
+ if !valid_syntax?( _action )
1068
+ raise "Error: bad action in Getopt::Declare specification:" +
1069
+ "\n\n#{_action}\n\n\n"
1070
+ end
1071
+
1072
+ if _args.length == 0
1073
+ raise "Error: unattached action in Getopt::Declare specification:\n#{_action}\n" +
1074
+ "\t(did you forget the tab after the preceding parameter specification?)\n"
1075
+ end
1076
+
1077
+ _args.last.actions.push( _action )
1078
+ next
1079
+ else
1080
+ if i =~ /\A(\s*[{].*)/
1081
+ raise "Error: incomplete action in Getopt::Declare specification:\n$1.....\n" +
1082
+ "\t(did you forget a closing '}'?)\n"
1083
+ end
1084
+ end
1085
+
1086
+
1087
+ # ARG + DESC:
1088
+ if i.sub!(re_argument,"")
1089
+ spec = "#$1".strip
1090
+ desc = "#$2"
1091
+ _strict ||= desc =~ /\[\s*strict\s*\]/
1092
+
1093
+ while i.sub!(re_more_desc,"")
1094
+ desc += "#$1"
1095
+ end
1096
+
1097
+ ditto = nil
1098
+ if _lastdesc and desc.sub!(/\A\s*\[\s*ditto\s*\]/,_lastdesc)
1099
+ ditto = arg
1100
+ else
1101
+ _lastdesc = desc
1102
+ end
1103
+
1104
+ # Check for GNU spec line like: -d, --debug
1105
+ arg = nil
1106
+ if spec =~ /(-[\w_\d]+),\s+(--?[\w_\d]+)(\s+.*)?/
1107
+ specs = ["#$1#$3", "#$2#$3"]
1108
+ specs.each { |spec|
1109
+ arg = Arg.new(spec,desc,ditto)
1110
+ _args.push( arg )
1111
+ _infer(desc, arg, _mutex)
1112
+ ditto = arg
1113
+ }
1114
+ else
1115
+ arg = Arg.new(spec,desc,ditto)
1116
+ _args.push( arg )
1117
+ _infer(desc, arg, _mutex)
1118
+ end
1119
+
1120
+
1121
+ next
1122
+ end
1123
+
1124
+ # OTHERWISE: DECORATION
1125
+ i.sub!(/((?:(?!\[\s*pvtype:).)*)(\n|(?=\[\s*pvtype:))/,"")
1126
+ decorator = "#$1"
1127
+ _strict ||= decorator =~ /\[\s*strict\s*\]/
1128
+ _infer(decorator, nil, _mutex)
1129
+
1130
+ _all_repeatable = true if decorator =~ /\[\s*repeatable\s*\]/
1131
+ @@debug = true if decorator =~ /\[\s*debug\s*\]/
1132
+
1133
+ end # while i.length
1134
+
1135
+
1136
+
1137
+ _lastactions = nil
1138
+ for i in _args
1139
+ if _lastactions && i.ditto && i.actions.size == 0
1140
+ i.actions = _lastactions
1141
+ else
1142
+ _lastactions = i.actions
1143
+ end
1144
+
1145
+ if _all_repeatable
1146
+ i.repeatable = 1
1147
+ end
1148
+ end
1149
+
1150
+ # Sort flags based on criteria described in docs
1151
+ # Sadly, this cannot be reduced to sort_by
1152
+ _args = _args.sort() { |a,b|
1153
+ cond1 = ( b.flag.size <=> a.flag.size )
1154
+ cond2 = ( b.flag == a.flag and ( b.args.size <=> a.args.size ) )
1155
+ cond3 = ( a.id <=> b.id )
1156
+ cond1 = nil if cond1 == 0
1157
+ cond2 = nil if cond2 == 0
1158
+ cond1 or cond2 or cond3
1159
+ }
1160
+
1161
+ # Handle clump
1162
+ clump = (@usage =~ /\[\s*cluster:\s*none\s*\]/i) ? 0 :
1163
+ (@usage =~ /\[\s*cluster:\s*singles?\s*\]/i) ? 1 :
1164
+ (@usage =~ /\[\s*cluster:\s*flags?\s*\]/i) ? 2 :
1165
+ (@usage =~ /\[\s*cluster:\s*any\s*\]/i) ? 3 :
1166
+ (@usage =~ /\[\s*cluster:(.*)\s*\]/i) ? "r" : 3
1167
+ raise "Error: unknown clustering mode: [cluster:#$1]\n" if clump == "r"
1168
+
1169
+ # CONSTRUCT OBJECT ITSELF
1170
+ @args = _args
1171
+ @mutex = _mutex
1172
+ @helppat = Arg::helppat()
1173
+ @verspat = Arg::versionpat()
1174
+
1175
+ @strict = _strict
1176
+ @clump = clump
1177
+ @source = ''
1178
+ @tight = @usage =~ /\[\s*tight\s*\]/i
1179
+ @caller = caller()
1180
+
1181
+ # VESTIGAL DEBUGGING CODE
1182
+ if @@debug
1183
+ f = File.new(".CODE.rb","w") and
1184
+ f.puts( code() ) and
1185
+ f.close()
1186
+ end
1187
+
1188
+ # DO THE PARSE (IF APPROPRIATE)
1189
+ if opts.size == 2
1190
+ return nil unless parse(source)
1191
+ else
1192
+ return nil unless parse()
1193
+ end
1194
+
1195
+ end # initialize
1196
+
1197
+
1198
+ # Parse the parameter description and in some cases,
1199
+ # optionally eval it, too.
1200
+ def parse(*opts)
1201
+ source = opts[0]
1202
+ _args = nil
1203
+ _get_nextline = proc { nil }
1204
+
1205
+ if source
1206
+ case source
1207
+ when Method
1208
+ _get_nextline = source
1209
+ _args = _get_nextline.call(self)
1210
+ source = '[METHOD]'
1211
+ when Proc
1212
+ _get_nextline = source
1213
+ _args = _get_nextline.call(self)
1214
+ source = '[PROC]'
1215
+ when IO
1216
+ if source.fileno > 0 && source.tty?
1217
+ _get_nextline = method(:_get_nextline)
1218
+ _args = $stdin.readline
1219
+ source = '<STDIN>'
1220
+ else
1221
+ _args = source.readlines.join(' ')
1222
+ _args.tr!('\t\n',' ')
1223
+ end
1224
+ when :build, :skip
1225
+ return 0
1226
+ when Array
1227
+ if source.length() == 1 && !source[0] ||
1228
+ source[0] == "-BUILD" ||
1229
+ source[0] == "-SKIP"
1230
+ return 0
1231
+ elsif source.length() == 2 && source[0] == "-ARGV"
1232
+ if !source[1] or !source[1] === Array
1233
+ raise 'Error: parse(["-ARGV"]) not passed an array as second parameter.'
1234
+ end
1235
+ _args = source[1].map { |i| i.tr( " \t\n", "\0\0\0" ) }.join(' ')
1236
+ source = '<ARRAY>'
1237
+ elsif source.length() == 1 && source[0] == "-STDIN"
1238
+ _get_nextline = method(:_get_nextline)
1239
+ _args = $stdin.readline
1240
+ source = '<STDIN>'
1241
+ elsif source.length() == 1 && source[0] == '-CONFIG'
1242
+ progname = "#{$0}rc"
1243
+ progname.sub!(%r#.*/#,'')
1244
+ home = ENV['HOME'] || ''
1245
+ _args, source = _load_sources( _get_nextline,
1246
+ [ home+"/.#{progname}",
1247
+ ".#{progname}" ] )
1248
+ else
1249
+ # Bunch of files to load passed to parse()
1250
+ _args, source = _load_sources( _get_nextline, source )
1251
+ end
1252
+ when String # else/case LITERAL STRING TO PARSE
1253
+ _args = source.dup
1254
+ source = source[0,7] + '...' if source && source.length() > 7
1255
+ source = "\"#{source[0..9]}\""
1256
+ else
1257
+ raise "Unknown source type for Getopt::Declare::parse"
1258
+ end # case
1259
+ return 0 unless _args
1260
+ source = " (in #{source})"
1261
+ else
1262
+ _args = ARGV.map { |i| i.tr( " \t\n", "\0\0\0" ) }.join(' ')
1263
+ source = ''
1264
+ end
1265
+
1266
+ @source = source
1267
+ begin
1268
+ err = eval( code(@caller) )
1269
+ if $@
1270
+ # oops, something wrong... exit
1271
+ puts "#{$!}: #{$@.inspect}"
1272
+ exit(1)
1273
+ end
1274
+ if !err
1275
+ exit(1)
1276
+ end
1277
+ rescue
1278
+ raise
1279
+ end
1280
+
1281
+
1282
+ true
1283
+ end
1284
+
1285
+ def type(*t)
1286
+ Getopt::Declare::ScalarArg::addtype(t)
1287
+ end
1288
+
1289
+ # Print out version information and maybe exit
1290
+ def version(*t)
1291
+ prog = "#{$0}"
1292
+ begin
1293
+ filedate = File.stat( prog ).mtime.localtime()
1294
+ rescue
1295
+ filedate = 'Unknown date'
1296
+ end
1297
+ prog.sub!(%r#.*/#,'')
1298
+ r = ''
1299
+ if defined?($VERSION)
1300
+ r << "\n#{prog}: version #{$VERSION} (#{filedate})\n\n"
1301
+ else
1302
+ r << "\n#{prog}: version dated #{filedate}\n\n"
1303
+ end
1304
+
1305
+ if t.empty?
1306
+ return r
1307
+ else
1308
+ puts r
1309
+ exit t[0]
1310
+ end
1311
+ end
1312
+
1313
+ # Print out usage information
1314
+ def usage(*opt)
1315
+
1316
+ t = @usage
1317
+
1318
+ lastflag = nil
1319
+ lastdesc = nil
1320
+ usage = ''
1321
+
1322
+ while !t.empty?
1323
+
1324
+ # COMMENT:
1325
+ t.sub!(/\A[ \t]*#.*\n/,".") and next
1326
+
1327
+ # TYPE DIRECTIVE:
1328
+ se = DelimScanner::new( t )
1329
+
1330
+ if t =~ /\A\s*\[\s*pvtype:/
1331
+ if action = se.extractBracketed("[")
1332
+ t.sub!(Regexp::quote( action ).to_re,'')
1333
+ t.sub!(/\A[ \t]*\n/,"")
1334
+ next
1335
+ end
1336
+ end
1337
+
1338
+ # ACTION
1339
+ codeblockDelimiters = {
1340
+ '{' => '}'
1341
+ }
1342
+ se = DelimScanner::new( t )
1343
+ if action = se.extractCodeblock(codeblockDelimiters)
1344
+ t.sub!(Regexp::quote( action ).to_re,'')
1345
+ t.sub!(/\A[ \t]*\n/,"")
1346
+ decfirst = 0 unless !decfirst.nil?
1347
+ next
1348
+ end
1349
+
1350
+
1351
+ # ARG + DESC:
1352
+ if t.sub!(re_argument,"")
1353
+ decfirst = 0 unless !decfirst.nil?
1354
+ spec = "#$1".expand_tabs!()
1355
+ desc = "#$2".expand_tabs!()
1356
+
1357
+ while t.gsub!(re_more_desc, '')
1358
+ desc += "#$1".expand_tabs!
1359
+ end
1360
+
1361
+ next if desc =~ /\[\s*undocumented\s*\]/i
1362
+
1363
+ uoff = 0
1364
+ spec.gsub!(/(<[a-zA-Z]\w*):([^>]+)>/e) { |i|
1365
+ uoff += 1 + "#$2".length() and "#$1>"
1366
+ }
1367
+ spec.gsub!(/\t/,"=")
1368
+
1369
+ ditto = desc =~ /\A\s*\[ditto\]/
1370
+ desc.gsub!(/^\s*\[.*?\]\s*\n/m,"")
1371
+ desc.gsub!(BracketDirectives,'')
1372
+ #desc.gsub!(/\[.*?\]/,"")
1373
+
1374
+
1375
+ if ditto
1376
+ desc = (lastdesc ? _ditto(lastflag,lastdesc,desc) : "" )
1377
+ elsif desc =~ /\A\s*\Z/
1378
+ next
1379
+ else
1380
+ lastdesc = desc
1381
+ end
1382
+
1383
+ spec =~ /\A\s*(\S+)/ and lastflag = "#$1"
1384
+
1385
+ desc.sub!(/\s+\Z/, "\n")
1386
+ usage += spec + ' ' * uoff + desc
1387
+ next
1388
+ end
1389
+
1390
+
1391
+
1392
+ # OTHERWISE, DECORATION
1393
+ if t.sub!(/((?:(?!\[\s*pvtype:).)*)(\n|(?=\[\s*pvtype:))/,"")
1394
+ desc = "#$1"+("#$2"||'')
1395
+ #desc.gsub!(/^(\s*\[.*?\])+\s*\n/m,'')
1396
+ #desc.gsub!(/\[.*?\]/,'') # eliminates anything in brackets
1397
+ if @tight || desc !~ /\A\s*\Z/
1398
+ desc.gsub!(BracketDirectives,'')
1399
+ next if desc =~ /\A\s*\Z/
1400
+ end
1401
+ decfirst = 1 unless !decfirst.nil? or desc =~ /\A\s*\Z/
1402
+ usage += desc
1403
+ end
1404
+
1405
+ end #while
1406
+
1407
+ required = ''
1408
+
1409
+ for arg in @args
1410
+ required += ' ' + arg.desc + ' ' if arg.required
1411
+ end
1412
+
1413
+ re1 = Regexp.new( '\255', nil, 'n' )
1414
+ usage.gsub!( re1 , "[/" ) # REINSTATE ESCAPED '['s
1415
+ # usage.gsub!(/\255/,"[/") # REINSTATE ESCAPED '['s
1416
+
1417
+ required.gsub!(/<([a-zA-Z]\w*):[^>]+>/,'<\1>')
1418
+ required.rstrip!
1419
+
1420
+ helpcmd = Getopt::Declare::Arg::besthelp
1421
+ versioncmd = Getopt::Declare::Arg::bestversion
1422
+
1423
+
1424
+ header = ''
1425
+ unless @source.nil?
1426
+ header << version()
1427
+ prog = "#{$0}"
1428
+ prog.sub!(%r#.*/#,'')
1429
+ header << "Usage: #{prog} [options]#{required}\n"
1430
+ header << " #{prog} #{helpcmd}\n" if helpcmd
1431
+ header << " #{prog} #{versioncmd}\n" if versioncmd
1432
+ header << "\n" unless decfirst && decfirst == 1 && usage =~ /\A[ \t]*\n/
1433
+ end
1434
+
1435
+ header << "Options:\n" unless decfirst && decfirst == 1
1436
+
1437
+ usage.sub!(/[\s\n]+\Z/m, '')
1438
+
1439
+ if opt.empty?
1440
+ return header + usage + "\n"
1441
+ end
1442
+
1443
+ pager = $stdout
1444
+ #begin
1445
+ # eval('require "IO/Pager";')
1446
+ # pager = IO::Pager.new()
1447
+ #rescue
1448
+ #end
1449
+
1450
+ #usage.sub!(/\A[\s\n]+/m, '')
1451
+ pager.puts "#{header}#{usage}"
1452
+ exit(opt[0]) if opt[0]
1453
+ end
1454
+
1455
+ attr_accessor :unused
1456
+
1457
+
1458
+ # Return list of used parameters (after parsing)
1459
+ def used
1460
+ used = @cache.keys
1461
+ return used.join(' ')
1462
+ end
1463
+
1464
+ @@m = []
1465
+
1466
+ # Main method to generate code to be evaluated for parsing.
1467
+ def code(*t)
1468
+ package = t[0] || ''
1469
+ code = %q%
1470
+
1471
+
1472
+ @_deferred = []
1473
+ @_errormsg = nil
1474
+ @_finished = nil
1475
+
1476
+ begin
1477
+
1478
+ begin
1479
+ undef :defer
1480
+ undef :reject
1481
+ undef :finish
1482
+ rescue
1483
+ end
1484
+
1485
+ def defer(&i)
1486
+ @_deferred.push( i )
1487
+ end
1488
+
1489
+ def reject(*i)
1490
+ if !i || i[0]
1491
+ @_errormsg = i[1] if i[1]
1492
+ throw :paramout
1493
+ end
1494
+ end
1495
+
1496
+ def finish(*i)
1497
+ if i.size
1498
+ @_finished = i
1499
+ else
1500
+ @_finished = true
1501
+ end
1502
+ end
1503
+
1504
+ @unused = []
1505
+ @cache = {}
1506
+ _FOUND_ = {}
1507
+ _errors = 0
1508
+ _invalid = {}
1509
+ _lastprefix = nil
1510
+
1511
+ _pos = 0 # current position to match from
1512
+ _nextpos = 0 # next position to match from
1513
+
1514
+ catch(:alldone) do
1515
+ while !@_finished
1516
+ begin
1517
+ catch(:arg) do
1518
+ @_errormsg = nil
1519
+
1520
+ # This is used for clustering of flags
1521
+ while _lastprefix
1522
+ substr = _args[_nextpos..-1]
1523
+ substr =~ /^(?!\s|\0|\Z)% +
1524
+ Getopt::Declare::Arg::negflagpat() + %q%/ or
1525
+ begin
1526
+ _lastprefix=nil
1527
+ break
1528
+ end
1529
+ "#{_lastprefix}#{substr}" =~ /^(% +
1530
+ Getopt::Declare::Arg::posflagpat() + %q%)/ or
1531
+ begin
1532
+ _lastprefix=nil
1533
+ break
1534
+ end
1535
+ _args = _args[0.._nextpos-1] + _lastprefix + _args[_nextpos..-1]
1536
+ break
1537
+ end # while _lastprefix
1538
+
1539
+ % + '' + %q%
1540
+ _pos = _nextpos if _args
1541
+
1542
+ usage(0) if _args && gindex(_args,/\G(% + @helppat + %q%)(\s|\0|\Z)/,_pos)
1543
+ version(0) if _args && _args =~ /\G(% + @verspat + %q%)(\s|\0|\Z)/
1544
+ %
1545
+
1546
+ for arg in @args
1547
+ code << arg.code(self,package)
1548
+ end
1549
+
1550
+ code << %q%
1551
+
1552
+ if _lastprefix
1553
+ _pos = _nextpos + _lastprefix.length()
1554
+ _lastprefix = nil
1555
+ next
1556
+ end
1557
+
1558
+ _pos = _nextpos
1559
+
1560
+ _args && _pos = gindex( _args, /\G[\s|\0]*(\S+)/, _pos ) or throw(:alldone)
1561
+
1562
+ if @_errormsg
1563
+ $stderr.puts( "Error#{source}: #{@_errormsg}\n" )
1564
+ else
1565
+ @unused.push( @@m[0] )
1566
+ end
1567
+
1568
+ _errors += 1 if @_errormsg
1569
+
1570
+ end # catch(:arg)
1571
+
1572
+ ensure # begin
1573
+ _pos = 0 if _pos.nil?
1574
+ _nextpos = _pos if _args
1575
+ if _args and _args.index( /\G(\s|\0)*\Z/, _pos )
1576
+ _args = _get_nextline.call(self) if !@_finished
1577
+ throw(:alldone) unless _args
1578
+ _pos = _nextpos = 0
1579
+ _lastprefix = ''
1580
+ end # if
1581
+ end # begin/ensure
1582
+ end # while @_finished
1583
+ end # catch(:alldone)
1584
+ end # begin
1585
+
1586
+ %
1587
+
1588
+
1589
+ ################################
1590
+ # Check for required arguments #
1591
+ ################################
1592
+ for arg in @args
1593
+ next unless arg.required
1594
+
1595
+ code << %q%unless _FOUND_['% + arg.name + %q%'] %
1596
+
1597
+ if @mutex[arg.name]
1598
+ for m in @mutex[arg.name]
1599
+ code << %q# or _FOUND_['# + m + %q#']#
1600
+ end
1601
+ end
1602
+
1603
+ code << %q%
1604
+ $stderr.puts "Error#{@source}: required parameter '% + arg.name + %q%' not found."
1605
+ _errors += 1
1606
+ end
1607
+ %
1608
+
1609
+ end
1610
+
1611
+ ########################################
1612
+ # Check for arguments requiring others #
1613
+ ########################################
1614
+
1615
+ for arg in @args
1616
+ next unless arg.requires
1617
+
1618
+ code << %q%
1619
+ if _FOUND_['% + arg.name + %q%'] && !(% + arg.found_requires +
1620
+ %q%)
1621
+ $stderr.puts "Error#{@source}: parameter '% + arg.name + %q%' can only be specified with '% + arg.requires + %q%'"
1622
+ _errors += 1
1623
+ end
1624
+ %
1625
+ end
1626
+
1627
+ code << %q%
1628
+ #################### Add unused arguments
1629
+ if _args && _nextpos > 0 && _args.length() > 0
1630
+ @unused.replace( @unused + _args[_nextpos..-1].split(' ') )
1631
+ end
1632
+
1633
+ for i in @unused
1634
+ i.tr!( "\0", " " )
1635
+ end
1636
+
1637
+ %
1638
+
1639
+ if @strict
1640
+ code << %q%
1641
+ #################### Handle strict flag
1642
+ unless _nextpos < ( _args ? _args.length : 0 )
1643
+ for i in @unused
1644
+ $stderr.puts "Error#{@source}: unrecognizable argument ('#{i}')"
1645
+ _errors += 1
1646
+ end
1647
+ end
1648
+ %
1649
+ end
1650
+
1651
+ code << %q%
1652
+ #################### Print help hint
1653
+ if _errors > 0 && !@source.nil?
1654
+ $stderr.puts "\n(try '#$0 % + Getopt::Declare::Arg::besthelp + %q%' for more information)"
1655
+ end
1656
+
1657
+ ## cannot just assign unused to ARGV in ruby
1658
+ unless @source != ''
1659
+ ARGV.clear
1660
+ @unused.map { |i| ARGV.push(i) }
1661
+ end
1662
+
1663
+ unless _errors > 0
1664
+ for i in @_deferred
1665
+ begin
1666
+ i.call
1667
+ rescue => e
1668
+ STDERR.puts "Action in Getopt::Declare specification produced:\n#{e}"
1669
+ _errors += 1
1670
+ end
1671
+ end
1672
+ end
1673
+
1674
+ !(_errors>0) # return true or false (false for errors)
1675
+
1676
+ %
1677
+ return code
1678
+ end
1679
+
1680
+
1681
+ # Inspect cache (not the declare object)
1682
+ def inspect
1683
+ return nil if !@cache
1684
+ t = ''
1685
+
1686
+ @cache.each { |a,b|
1687
+ t << a + " => "
1688
+ case b
1689
+ when Hash
1690
+ t << "{"
1691
+ i = []
1692
+ b.each { |c,d|
1693
+ i.push( " '#{c}' => " + d.inspect )
1694
+ }
1695
+ t << i.join(',')
1696
+ t << " }"
1697
+ else
1698
+ t << b.inspect
1699
+ end
1700
+ t << "\n"
1701
+ }
1702
+ t << "Unused: " + unused.join(', ')
1703
+ end
1704
+
1705
+ # Iterator for Getopt::Declare (travels thru all cache keys)
1706
+ def each(&t)
1707
+ @cache.each(&t)
1708
+ end
1709
+
1710
+ # Operator to easily create new value in of Getopt::Declare
1711
+ def []=(name,val)
1712
+ @cache = {} unless @cache
1713
+ @cache[name] = val
1714
+ end
1715
+
1716
+ # Operator to easily return cache of Getopt::Declare
1717
+ def [](name)
1718
+ if @cache
1719
+ return @cache[name]
1720
+ else
1721
+ return nil
1722
+ end
1723
+ end
1724
+
1725
+ # Operator to return number of flags set
1726
+ def size
1727
+ return 0 unless @cache
1728
+ return @cache.keys.size
1729
+ end
1730
+
1731
+ attr :mutex
1732
+ attr :helppat
1733
+ attr :verspat
1734
+ attr :strict
1735
+ attr :clump
1736
+ attr :source
1737
+
1738
+ end # class Declare
1739
+
1740
+ end # module Getopt