-
Notifications
You must be signed in to change notification settings - Fork 0
/
xoptions.icn
861 lines (848 loc) · 39.4 KB
/
xoptions.icn
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
############################################################################
#
# File: xoptions.icn
#
# Subject: Procedure to get command-line options
#
# Based on the options.icn by
# Robert J. Alexander and Gregg M. Townsend and Don Ward
#
# Modified: Bruce Rennie Rewrite and extensions
#
# Date: August 29, 2020
#
############################################################################
#
# This file is in the public domain.
#
############################################################################
#
# xoptions(arg, optstring, errproc, finishoption[]) removes command options
# from the argument list of an Icon main procedure, returning a table of
# option values.
#
############################################################################
#
# xoptions(arg, optstring, errproc, finishoption[]) -- Get command line options.
#
# This procedure separates and interprets command line options included in
# the main program argument list. Option names and values are removed
# from the argument list and returned in a table. Allows for options to have
# sub-options and allows for options/sub-options to be stored in separate files
# and called by referencing these files by use of "@".
#
# This procedure will now handle the POSIX conventions, the GNU long option
# conventions and the various conventions that were originally in this procedure,
# including non-alphanumeric characters as options.
#
# Additionally, Icon/Unicon conventions of using "-x" as well as "--" to end
# the processing of options from the command line by allowing an additional list
# of values to do this. A addition allows for a series of values to be stored
# against an option till "--" or other specified values are encountered.
#
# On the command line, options are introduced by a "-" character. An option
# name is either a single printable character, as in "-n" or "-?", or a string
# of letters, numbers, and underscores, as in "-geometry". Valueless
# single-character options may appear in combination, for example as "-qtv".
#
#
# Some options require values. Generally, the option name is one argument
# and the value appears as the next argument, for example "-F file.txt".
# However, with a single-character argument name (as in that example), the
# value may be concatenated: "-Ffile.txt" is accepted as equivalent. In addition
# the "=" can be used as the separator between the option and the value (no
# space separation allowed) as in "-F=file.txt".
#
# Options may be freely interspersed with non-option arguments. An argument
# of a single "-" is treated as a non-option. The special argument "--" or other
# specified values will terminate the option processing. Non-option arguments
# are returned in the original argument list for interpretation by the caller,
# including those collected from any specified option file (as described in the
# next paragraph).
#
# An argument of the form @filename (a "@" immediately followed by a file name)
# causes xoptions() to replace that argument with arguments retrieved from the
# file "filename". Each line of the file is taken as a separate argument,
# exactly as it appears in the file. Arguments beginning with - are processed
# as options, and those starting with @ are processed as nested argument files.
# An argument of "--" causes all remaining arguments IN THAT FILE ONLY to be
# treated as non-options (including @filename arguments). filename can have a
# fully specified path or a relative specified path or a local directory
# specified path.
#
# The parameters of xoptions(arg, optstring, errproc, finishoption[]) are:
#
# arg the argument list as passed to the main procedure. This is the
# list that is passed into the program from the operating system
# being used.
#
# optstring a string specifying the allowable options. This is a
# concatenation, with optional spaces between, of one or more
# option specs of the form
#
# -name%* (one or more alphanumeric or _)
# --name%* (one or more alphanumeric or _ or -)
# name%* (one or more characters not flags and each
# character is treated as a separate single
# character option)
# =name%* (one or more alphanumeric or _)
#
# where
#
# - introduces the option
#
# -- introduces the option where the option name can
# contain "-"
#
# = introduces the option where command line option
# can be either --name or -name
#
# name is either a string of alphanumerics (any of a-z,
# A-Z, 0-9, and _)
# or any single printable character. The "-" is
# allowed when prefixed by "--".
#
# % is one of the following flag characters:
# ! No value is required or allowed
# : A string value is required
# + An integer value is required
# . A real value is required
# $ Optional value - anything
# () Defines a set of comma separated sub-option
# option/pairs. The option string definition
# use the above flag characters "!", ":",
# "+", ".", "$" with an optional "*". The
# value (if supplied) is separated by "=".
# < all values following this option up to any
# value found in finishoption are to be
# collected into a list for this option.
# any "*" following this will be ignored.
#
# * optional and indicates that the option can occur
# multiple times in the command options and must
# follow the % specifier, if used.
#
# For all options that do not allow multiple occurrences,
# the consequence of multiple appearances of that option
# is that the last occurrence will overwrite any previous
# occurrence.
#
# The leading "-" may be omitted for a single-characteroption.
# The "!" flag may be omitted except when needed to terminate
# a multi-character name. In the case of a single "-" as the
# start of the option specifier, any following "-" will
# terminate the multi-character name.
#
# Thus the following optstrings are equivalent:
#
# "-n+ -t -v -q -F: -geometry: -silent"
# "n+tvqF:-geometry:-silent"
# "-silent!n+tvqF:-geometry:"
#
# If "optstring" is omitted any single letter or digit is
# assumed to be valid and require no data.
#
# errproc a procedure which will be called if an error is is detected
# in the command line options. The procedure is called with
# one argument: a string describing the error that occurred.
# After errproc() is called, xoptions() immediately returns the
# outcome of errproc(), without processing further arguments.
# Already processed arguments will have been removed from "arg".
# If "errproc" is omitted, stop() is called if an error is
# detected and the program will abort.
#
# finishoption is a list of options that terminate the processing of options.
# This allows the proceeding options to be passed to another
# program. By default this is "--". An example of other values
# being used is the "-x" used in the icont compiler to pass
# all following parameters to the iconx interpreter.
#
#
# A table is returned containing the options that were specified. The keys
# are the specified option names. The assigned values are the data values
# following the options converted to the specified type.
#
# A value of 1 is stored for options that accept no values.
#
# The table's default value is &null so testing for the occurrence of that
# specific parameter can use the \ operator to check if it was actually specified
# on the command line.
#
#
# Upon return, the option arguments are removed from arg, leaving only the
# non-option arguments.
#
#
# Options with embedded "-"
#
# Options may begin with "--" and, if they do, may contain "-" characters.
# So options like --dry-run will be parsed correctly and will result in an
# entry in the options table with a key of "-dry-run" (note the leading minus
# in the key). All such options must be terminated by a space or one of
# allowable specifier characters described above. The handling of these options
# allows any number of "-" to be in the option name after the initial
# alphanumeric or "_" character. The normal expectation is that the option name
# will have a single "-" between each group of alphanumeric character grouping.
# However, if you require multiple sequential "-" in the option name, this is
# allowed.
#
# For all options that have an associated value (optional or required), there
# are three usable alternatives (as per POSIX standards).
#
# For single character options, the value can follow immediately, or it can be
# space separated or have a an "=" between the option and the value.
#
# Using -l as an example, we can specify the command line as
#
# -lone
# -l one
# -l=one
#
# For multi-character options, the value is either space separated or have
# an "=" between the option and the value.
#
# Using -geometry as an example, we can specify the command line as
#
# -geometry "240:240"
# -geometry="240:240"
#
# For options that have sub-options the following has been added (as per the
# POSIX standards). The options that have sub-options have the sub-options as a
# comma separated list of option/value pairs. Those sub-options that have values use
# a "=" between sub-option and the associated value. To define the sub-options,
# place these in parentheses.
#
# An example of defining the option string.
#
# -o(h!file:*sfr)
#
# The command line form could be as follows
#
# -o h,file=filename.ext,file="another file.ext",r
#
# The value returned for an option that has sub-options is a table of key/values
# pairs, the default is &null and for keys that have no required values, the value
# returned is 1.
#
#
# A similar extension is available in the @ file. You can now write
#
# -time 45
# or
# -time=45
#
# instead of the two lines previously required as in
#
# -time
# 45
#
# Treating options specified as --opt and -opt as the same option.
#
# To remove the leading minus from such keys, make the first character
# of the specified option in the option string an "=" character: then, a
# supplied argument of either --opt or -opt would result in a key of "opt" in
# the table. When the first character is an equals character, the procedure
# ensures that only one of "--opt" or "-opt" may be specified in the option
# way to allow (for example) both --run and -run as options is to miss out
# string. The only the leading equals and to treat option["-run"] and option["run"]
# separately in the calling program.
#
# e.g.
#
# "-bish-bash-bosh--bash" gives to four different options, which are
#
# command line option table
# ------------------------------|-----------------------------
# -bish | bish
# -bash | bash
# -bosh | bosh
# --bash | -bash
#
# "--bish-bash-bosh--bash" recognises a single command line option
#
# command line option table
# ------------------------------|-----------------------------
# --bish-bash-bosh--bash | -bish-bash-bosh--bash
#
# "=bish-bash-bosh--bash" recognises two command line options that have the
# same meaning
#
# command line option table
# ------------------------------|-----------------------------
# -bish-bash-bosh--bash | bish-bash-bosh--bash
# --bish-bash-bosh--bash | bish-bash-bosh--bash
#
#
# Specify short form of option names
#
# As per GNU extensions, the option names can be shortened as long as these
# shortened forms are able to be disambiguated from all other valid option
# names. An example of this would be two options such as "-si" and "-silent".
#
# In this case, "-s" would NOT be a valid short form as it could not be
# disambiguated between either of the options. "-si" would be available as this
# is the full option name and "-sil" and any longer prefix of "-silent" would
# also be valid.
#
# The command line could use the full names as:
#
# "-si -silent"
#
# or it could be specified as
#
# "-si -sil"
#
# as being equivalent command line forms.
#
############################################################################
#PD:
#: xoptions(arg, optstring, errproc, finishoption[])
#:
#:@param arg list of strings which represent the arguments given
#:@ to the calling program
#:@param optstring string representing the allowable options and sub-options
#:@ and any required values for those options/sub-options
#:@errproc error procedure to be used when an error is found in
#:@ the supplied arg list
#:@finishoption[] list of applicable values that can terminate the
#:@ processing of options and values
#:@returns table containing option/values found in the arg list
#:@updates arg the value of arg is updated by the removal the found
#:@ options/values and by pointer semantics, the value in
#:@ calling procedure
#:
procedure xoptions(arg, optstring, errproc, finishoption[])
local opttable, #LV: table whose keys are the various options
#: that have been specified in the parameter
#: "optstring" and the value is the option
#: type found in the parameter "optstring"
option, #LV: table holding currently found options
#: in the arg list
flags, #LV: cset holding the valid option flag
#: values
maptable, #LV: maps valid command line short form
#: parameters to full names of parameters
tmpt #LV: temporary variable
#
# if no optstring is supplied, then set the default value to a string consisting
# of the alphanumeric characters. The default does not allow for values that
# can be supplied by the user.
#
/optstring := string(&letters ++ &digits)
#
# the default error processing is to call the system stop() function
#
/errproc := stop
#
# the normal default value for terminating option processing is "--", the icont
# and unicon both use "-x" as a different terminating value for option processing
#
*finishoption = 0 & finishoption := ["--"]
option := table()
#
# the valid flags are set here. See the allowable characters in the desrciption
# above.
#
flags := "!:+.$(<"
#
# Scan the option specification string.
#
tmpt := process_option_string(optstring, flags)
#
# Two tables are returned for the actual processing of the command line options.
# The first is the option specifier table and the second is the short form
# to option name mapping table.
#
opttable := tmpt[1]
maptable := tmpt[2]
#
# Process the argument list, using option specifier table and mapping table.
#
return process_command_option(arg, option, opttable, maptable, finishoption, errproc)
end
#PD:
#: process_option_string(optstring, flags, nosuboption)
#:
#:
procedure process_option_string(optstring, flags, nosuboption)
local optname, #LV: the name of the current option being
#: processed from "optstring"
opttable, #LV: table whose keys are the various options
#: that have been specified in the parameter
#: "optstring" and the value is the option
#: type found in the parameter "optstring"
opttype, #LV: holds the option type for the current
#: option being processed from "optstring"
optcs, #LV: cset for valid option characters
#: which are the alphanumeric and _ characters
minusoptcs, #LV: cset for valid option characters when
#: a -- pair is found, these are the
#: alphanumeric, _ and - characters.
suboption, #LV: holds the suboption sequence for processing
maptable, #LV: maps valid command line short form parameters
#: to full names of parameters
tkey, #LV: used to sequence through options table keys
#: to calculate the valid short form names
#: applicable to an option.
str, #LV: used as the option name value to calculate
#: the valid short form name.
i, #LV: index into the option name to select
#: the next short form name.
cannotshorten, #LV: holds the table of option names that
#: cannot be shortened due to ambiguities
#: between option names
skey, #LV: used to find option names that cannot
#: be shortened.
prefixset #LV: table containing all valid short forms
#: as keys with the value as a set of
#: applicable options. These will be removed
#: from the maptable as the last process
#
# Initialise the various variables with their required values.
#
# if no optstring is supplied, then set the default value to a cset consisting
# of the alphanumeric characters. The
#
/optstring := string(&letters ++ &digits)
#
opttable := table()
#
# the valid option name characters allowed for multi-character option names
#
optcs := &letters ++ &digits ++ '_'
minusoptcs := optcs ++ '-'
#
# this table holds each valid short form option name and refers this back to
# the full valid option name. An example of this is:
#
# if two options are specified are -si and -silent, this table will hold
# the following key/value pairs
#
# key value
# ----------------|------------------
# si | si
# sil | silent
# sile | silent
# silen | silent
# silent | silent
#
# the short "s" is not a valid short form, since it cannot be disambiguated
#
maptable := table()
cannotshorten := table()
#
# Scan the option specification string.
#
optstring ? {
while optname := move(1) do {
#
# this will skip each space character found in the parameter "optstring"
# where the space is not found between "" or '' pairs
#
if optname == " " then {
tab(many(' '))
next
}
#
# if we see a "-" as the option name then we will expect either a
# sequence of characters as specified in optcs or a second "-". get
# the option name
#
if optname == "-" then {
optname := move(1) | break
#
# if the next character is a member of the option name set then
# collect these into the optname
#
if member(optcs, optname) then {
optname ||:= tab(many(optcs))
maptable[optname] := optname
#
# we check to see if this character is a "-" then collect any
# characters that follow that are members of the extended option name
# set and collect these into the option name
#
} else if optname == "-" then {
optname ||:= tab(many(minusoptcs))
maptable[optname] := optname
} else {
maptable[optname] := optname
}
#
# we next look for the "=" as the start for the next option
#
} else if optname == "=" then {
optname := move(1) | break
#
# if the next character is a member of the option name set then
# collect these into the optname
#
if member(minusoptcs, optname) then {
optname ||:= tab(many(minusoptcs))
maptable[optname] := optname
maptable["-" || optname] := optname
} else {
maptable[optname] := optname
maptable["-" || optname] := optname
}
} else {
maptable[optname] := optname
}
#
# We now determine the option type from the valid possibilities and
# if not found, we will make it "!"
#
opttype := tab(any(flags)) | "!"
#
# check if the flag indicates that suboption processing is required
#
if /nosuboption then {
if opttype == "(" then {
suboption := tab(upto(")"))
move(1)
opttype := process_option_string(suboption, flags -- '(', 1)
}
}
#
# the last possibility for the option type to be checked is if there
# option multiplicity indicator to be found. If it is, convert opttype
# to a list value.
#
if ="*" then {
if opttype ~== "<" then {
opttype := [opttype]
}
}
#
# we have found the option and and its associated option type, so
# we can enter it into the local option table by which we will process
# the supplied arguments. This value will be either a character or a
# table of suboption pairs or a list containing a character or a table.
#
opttable[optname] := opttype
}
}
#
# determine the valid short forms applicable for each option.
#
# There will be certain options that are prefixes of other options and as a
# consequence of this cannot be shortened. here we determine which of the options
# this condition applies to
#
every tkey := key(maptable) do {
if match(tkey, skey := key(maptable)) & tkey ~== skey then {
cannotshorten[tkey] := 1
}
}
#
# we no determine all of the short forms that can occurrences. However, this
# does add a number of short forms which are not valid. These will be removed
# later
#
every tkey := key(maptable) do {
str := maptable[tkey]
every i := *str to 2 by -1 do {
(/cannotshorten[str] & /maptable[str[1:i]] := str) | break
}
}
#
# To determine which of the short forms need to be removed, we need to determine
# what options each of the short forms could be a prefix to. We will use a set
# to hold the different options applicable
#
prefixset := table()
every tkey := key(maptable) do {
#
# we add to the set the option applicable from the maptable
#
prefixset[tkey] := set([maptable[tkey]])
#
# find any other option where the current tkey is a prefix and the applicable
# options do not match and the tkey does not match the applicable option itself
# and the length of the short form is less than or equal to the option. This
# last requirement takes care of any situation where an "=" has been used in
# the option definition above
#
if match(tkey, str := key(maptable)) &
maptable[tkey] ~== maptable[str] &
maptable[tkey] ~== tkey & *tkey <= *maptable[tkey] then {
insert(prefixset[tkey], maptable[str])
}
}
#
# we look at each of the short forms and if it has more than 1 applicable optional
# we remove this from the maptable
#
every tkey := key(prefixset) do {
if *prefixset[tkey] > 1 then {
delete(maptable, tkey)
}
}
return [opttable, maptable]
end
#PD:
#: process_command_option(args, option, opttable, maptable, finishoption, errproc, nosuboption)
#:
#:
procedure process_command_option(args, option, opttable, maptable, finishoption, errproc, nosuboption)
local f, #LV: temporary to hold a file descriptor if
#: a @filename is found in arg list
fList, #LV: holds accumulating list of arguments
#: that are not options or option values
fn, #LV: holds the current filename found @filename
optname, #LV: the name of the current option being
#: processed from "optstring"
opttype, #LV: holds the option type for the current
#: option being processed from "optstring"
p, #LV: holds the current option value found
x, #LV: current argument being processed
suboptionsep, #LV: holds the suboption separator character
tmpopt, #LV: temporary to hold the current option value
mulopt, #LV: flag to indicate if the current option
#: allows multiple occurrences
argstack, #LV: stack of arg lists, allows @filenames
#: to be used uniformly without special
#: treatment of an argument
currentarg, #LV: the current arg list being processed
tmpx, #LV: temporary variable
tmpstr, #LV: temporary variable
tmplst #LV: temporary variable
#
# for those options that allow sub-options, this is the character that separates
# each sub-options
#
suboptionsep := ","
argstack := []
currentarg := args
fList := []
while x := \get(currentarg) do {
x ? {
#
# if any of the finish processing options are found, we will push
# the current argument being tested back onto the current arg list,
# append this list to the accumulating non-option arguments and pop
# the arg stack for any further processing
#
if =!finishoption & pos(0) then {
fList |||:= currentarg
currentarg := []
#
# no finish processing option has been found, test against the
# valid set of options
#
} else if ="-" & not pos(0) then {
(tmpx := tab(0)) ? until pos(0) do {
#
# if the option is a valid option as specified in the
# optstring, we will process it according to its specification
#
if opttype := \opttable[(optname := (((pos(1),tab(find("=") | 0)) | maptable[optname]) |
(move(1) | maptable[optname])))] then {
#
# since we allow the possibility of an option to occur
# multiple times in the arg list, we need to check
# if the type of the current option is one of these.
# this will be a list value
# If it is then the values found are stored in a list
# and set the flag to indicate this
#
="="
if type(opttype) == ("list") & *opttype = 1 then {
/option[optname] := []
mulopt := 1
opttype := opttype[1]
} else {
mulopt := &null
}
tmpopt :=
#
# we check for the suboption case first, which means
# that the opttype will be a list of size 2
#
if type(opttype) == "list" then {
#
# check the size of this list to make sure it is
# of size 2
#
if *opttype = 2 then {
process_command_option(convert_to_list(get(currentarg), suboptionsep), table(), opttype[1], opttype[2], finishoption, errproc, 1)
#
# we have somehow managed to get an error here. this
# should not have been possible
#
} else {
stop("This error should NEVER occur!!!!!!!\n\nProcessing of sub-options has given rise to a critical error!!!!\n")
}
#
# we check for the required value cases second,
# at this point in time, these types are ":", "+"
# and "."
#
} else if any(':+.',opttype) then {
#
# required value immediately follows the option or
# is the next argument in the arg list
#
p := "" ~== trim(tab(0) | get(currentarg), ' ', 0) |
return errproc("No parameter following -" ||
optname)
#
# depending on the option, we may have to coerce
# the value to the correct unicon base type. This
# value is result for the assignment above.
#
case opttype[1] of {
":" : {
trim(p, ' ', 0)
}
"+" : {
integer(p) |
return errproc("-" || optname ||
" needs numeric parameter")
}
"." : {
real(p) |
return errproc("-" || optname ||
" needs numeric parameter")
}
}
#
# we will now check for optional values and if found
# this will be treated as a string value for the
# assignment
#
} else if opttype[1] == "$" then {
#
# optional value immediately follows the option or
# is the next argument in the arg list. if a valid
# option is found, then there is no optional value
# and we need to restore the option found back to
# the argument list
#
p := "" ~== trim(tab(0) | get(args), ' ', 0)
if match("-", p) then {
push(args, p)
p := 1
}
p
#
# collect all following parameters into a list up to the end
# or one of the values found in finishoptions
#
} else if opttype[1] == "<" then {
tmplst := []
while p := get(currentarg) do {
if p == !finishoption then {
push(currentarg, p)
break
} else {
put(tmplst, p)
}
}
tmplst
#
# all options that do not have associated values are
# given a default value of 1 to indicate their presence
# in the arg list
#
} else {
1
}
#
# if this option allows multiple occurrences, put the option
# value onto the list of values found for this option
#
if \mulopt then {
put(option[optname], trim(tmpopt, ' ', 0))
#
# otherwise we just overwrite any previous value that
# has been found for this option
#
} else {
option[optname] := tmpopt
}
tab(0)
#
# the option found is not know and so we will handled this
# by the user specified error procedure, which defaults to
# a program stop if the user has not specified any such
# error handling
#
} else {
tmpstr := "Unrecognized option: -" || tmpx || "\nThis is either not a valid "
tmpstr ||:= (/nosuboption & "option") | "sub-option"
tmpstr ||:= " or not a valid short form name of the "
tmpstr ||:= (/nosuboption & "option") | "sub-option"
tmpstr ||:= "\n\nValid "
tmpstr ||:= (/nosuboption & "option") | "sub-option"
tmpstr ||:= "s are :\n"
tmplst := sort(opttable)
every tmpstr ||:= " " || tmplst[1 to *tmplst][1] || "\n"
return errproc(tmpstr)
}
}
#
# If the argument begins with the character "@", push the current
# arg list onto the arg stack and create a new current arg list,
# fetch option words from lines of a text file and push onto the
# current arg list for subsequent processing.
#
} else if ="@" & not pos(0) then {
push(argstack, currentarg)
f := open(fn := tab(0)) |
return errproc("Can't open " || fn)
currentarg := []
while put(currentarg, read(f))
close(f)
option := process_command_option(currentarg, option, opttable, maptable, finishoption, errproc, 1)
fList |||:= currentarg
currentarg := pop(argstack)
#
# argument is not an option and so we append it to the accumulating
# arguments
#
} else {
put(fList,x)
}
}
}
#
# clear the args list of any remaining values. Since we are using pointer semantics,
# this will affect the list in the calling procedure.
#
while pop(args)
#
# put onto the args list all values that have been collected. The pointer semantics
# will ensure that the list in the calling procedure will be updated accordingly.
#
while push(args, pull(fList))
return option
end
#PD:
#: convert_to_list(str, suboptionsep) - the sub-string elements that are separated
#: by the value found in suboptionsep into a list of strings that are option/value
#: pairs and prefix each sub-string with the "-".
#:
#: This procedure is helper procedure to allow processing of sub-options as if
#: they were an argument list.
#:
procedure convert_to_list(str, suboptionsep)
local lst, #LV: resultant list value to be returned
element #LV: the element from the supplied string
lst := []
str ? {
until pos(0) do {
if element := tab(find(suboptionsep)) then {
put(lst, "-" || element)
move(1)
#
# the last sub-option will not have a following suboptionsep, so we just
# take the option/value pair as ending at the end of the supplied strings
#
} else {
put(lst, element := "-" || tab(0))
}
}
}
return lst
end