getopt-declare 1.25 → 1.26

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