xref: /openbsd-src/usr.bin/libtool/LT/Getopt.pm (revision f41ccc36c98bb70900c901ba8385dbb26f3cea97)
1*f41ccc36Sespie# $OpenBSD: Getopt.pm,v 1.14 2023/07/06 08:29:26 espie Exp $
2c84241d1Sespie
3c84241d1Sespie# Copyright (c) 2012 Marc Espie <espie@openbsd.org>
4c84241d1Sespie#
5c84241d1Sespie# Permission to use, copy, modify, and distribute this software for any
6c84241d1Sespie# purpose with or without fee is hereby granted, provided that the above
7c84241d1Sespie# copyright notice and this permission notice appear in all copies.
8c84241d1Sespie#
9c84241d1Sespie# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10c84241d1Sespie# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11c84241d1Sespie# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12c84241d1Sespie# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13c84241d1Sespie# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14c84241d1Sespie# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15c84241d1Sespie# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16c84241d1Sespie#
17c84241d1Sespie
18*f41ccc36Sespieuse v5.36;
19c84241d1Sespie
20c84241d1Sespiepackage Option;
21*f41ccc36Sespiesub factory($class, $o)
22c84241d1Sespie{
2328252c27Safresh1	if ($o =~ m/^(.)$/) {
24c84241d1Sespie		return Option::Short->new($1);
2528252c27Safresh1	} elsif ($o =~ m/^(.)\:$/) {
26c84241d1Sespie		return Option::ShortArg->new($1);
2728252c27Safresh1	} elsif ($o =~ m/^(\-?.)(?:\:\!|\!\:)$/) {
285bf01557Sespie		return Option::LongArg0->new($1);
2928252c27Safresh1	} elsif ($o =~ m/^(\-?.)\!$/) {
305bf01557Sespie		return Option::Long->new($1);
3128252c27Safresh1	} elsif ($o =~ m/^(\-?.*)\=$/) {
32c84241d1Sespie		return Option::LongArg->new($1);
3328252c27Safresh1	} elsif ($o =~ m/^(\-?.*)\:$/) {
34deab3a89Sespie		return Option::LongArg0->new($1);
3528252c27Safresh1	} elsif ($o =~ m/^(\-?.*)$/) {
36c84241d1Sespie		return Option::Long->new($1);
37c84241d1Sespie	}
38c84241d1Sespie}
39c84241d1Sespie
40*f41ccc36Sespiesub new($class, $v)
41c84241d1Sespie{
42c84241d1Sespie	bless \$v, $class;
43c84241d1Sespie}
44c84241d1Sespie
45*f41ccc36Sespiesub setup($self, $opts, $isarray)
46c84241d1Sespie{
47d38c979aSespie	$opts->add_option_accessor($$self, $isarray);
48d38c979aSespie	return $self;
49c84241d1Sespie}
50c84241d1Sespie
51d38c979aSespiepackage Option::Short;
52d38c979aSespieour @ISA = qw(Option);
53d38c979aSespie
54*f41ccc36Sespiesub match($self, $arg, $opts, $canonical, $code)
55c84241d1Sespie{
5628252c27Safresh1	if ($arg =~ m/^\-\Q$$self\E$/) {
5728252c27Safresh1		&$code($opts, $canonical, 1, $arg);
58c84241d1Sespie		return 1;
59c84241d1Sespie	}
6028252c27Safresh1	if ($arg =~ m/^(\-\Q$$self\E)(.*)$/) {
616bcc3551Sespie		unshift(@main::ARGV, "-$2");
626bcc3551Sespie		&$code($opts, $canonical, 1, $1);
63c84241d1Sespie		return 1;
64c84241d1Sespie	}
65c84241d1Sespie	return 0;
66c84241d1Sespie}
67c84241d1Sespie
68c84241d1Sespiepackage Option::ShortArg;
69c84241d1Sespieour @ISA = qw(Option::Short);
70c84241d1Sespie
71*f41ccc36Sespiesub match($self, $arg, $opts, $canonical, $code)
72c84241d1Sespie{
7328252c27Safresh1	if ($arg =~ m/^\-\Q$$self\E$/) {
7428252c27Safresh1		&$code($opts, $canonical, (shift @main::ARGV), $arg);
75c84241d1Sespie		return 1;
76c84241d1Sespie	}
7728252c27Safresh1	if ($arg =~ m/^(\-\Q$$self\E)(.*)$/) {
786bcc3551Sespie		&$code($opts, $canonical, $2, $1);
79c84241d1Sespie		return 1;
80c84241d1Sespie	}
81c84241d1Sespie	return 0;
82c84241d1Sespie}
83c84241d1Sespie
84c84241d1Sespiepackage Option::Long;
85c84241d1Sespieour @ISA = qw(Option);
86c84241d1Sespie
87*f41ccc36Sespiesub match($self, $arg, $opts, $canonical, $code)
88c84241d1Sespie{
8928252c27Safresh1	if ($arg =~ m/^\-\Q$$self\E$/) {
9028252c27Safresh1		&$code($opts, $canonical, 1, $arg);
91c84241d1Sespie		return 1;
92c84241d1Sespie	}
93c84241d1Sespie	return 0;
94c84241d1Sespie}
95c84241d1Sespie
96deab3a89Sespiepackage Option::LongArg0;
97c84241d1Sespieour @ISA = qw(Option::Long);
98*f41ccc36Sespiesub match($self, $arg, $opts, $canonical, $code)
99c84241d1Sespie{
10028252c27Safresh1	if ($arg =~ m/^\-\Q$$self\E$/) {
101c84241d1Sespie		if (@main::ARGV > 0) {
10228252c27Safresh1			&$code($opts, $canonical, (shift @main::ARGV), $arg);
103c84241d1Sespie			return 1;
104c84241d1Sespie		} else {
105c84241d1Sespie			die "Missing argument  for option -$$self\n";
106c84241d1Sespie		}
107c84241d1Sespie	}
108deab3a89Sespie	return 0;
109deab3a89Sespie}
110deab3a89Sespie
111deab3a89Sespiepackage Option::LongArg;
112deab3a89Sespieour @ISA = qw(Option::LongArg0);
113deab3a89Sespie
114*f41ccc36Sespiesub match($self, $arg, $opts, $canonical, $code)
115deab3a89Sespie{
11628252c27Safresh1	if ($self->SUPER::match($arg, $opts, $canonical, $code)) {
117deab3a89Sespie		return 1;
118deab3a89Sespie	}
11928252c27Safresh1	if ($arg =~ m/^(-\Q$$self\E)\=(.*)$/) {
1206bcc3551Sespie		&$code($opts, $canonical, $2, $1);
121c84241d1Sespie		return 1;
122c84241d1Sespie	}
123c84241d1Sespie	return 0;
124c84241d1Sespie}
125c84241d1Sespie
12692d5e529Sespiepackage Option::Regexp;
127*f41ccc36Sespiesub new($class, $re, $code)
12892d5e529Sespie{
12992d5e529Sespie	bless {re => $re, code => $code}, $class;
13092d5e529Sespie}
13192d5e529Sespie
132*f41ccc36Sespiesub setup($self, $, $)
13392d5e529Sespie{
134*f41ccc36Sespie	return $self;
13592d5e529Sespie}
13692d5e529Sespie
137*f41ccc36Sespiesub match($self, $arg, $opts)
13892d5e529Sespie{
13992d5e529Sespie	if (my @l = ($arg =~ m/^$self->{re}$/)) {
14092d5e529Sespie		&{$self->{code}}(@l);
14192d5e529Sespie		return 1;
14292d5e529Sespie	} else {
14392d5e529Sespie		return 0;
14492d5e529Sespie	}
14592d5e529Sespie}
14692d5e529Sespie
147c84241d1Sespiepackage Options;
148c84241d1Sespie
149*f41ccc36Sespiesub new($class, $string, $code)
150c84241d1Sespie{
15192d5e529Sespie	if (ref($string) eq 'Regexp') {
15292d5e529Sespie		return Option::Regexp->new($string, $code);
15392d5e529Sespie	}
154c84241d1Sespie	my @alternates = split(/\|/, $string);
155c84241d1Sespie
156*f41ccc36Sespie	bless {
157*f41ccc36Sespie		alt => [map { Option->factory($_); } @alternates],
158*f41ccc36Sespie		code => $code
159*f41ccc36Sespie	}, $class;
160c84241d1Sespie}
161c84241d1Sespie
162*f41ccc36Sespiesub setup($self, $allopts, $isarray)
163c84241d1Sespie{
164d38c979aSespie	$self->{alt}[0]->setup($allopts, $isarray);
165c84241d1Sespie	return $self;
166c84241d1Sespie}
167c84241d1Sespie
168*f41ccc36Sespiesub match($self, $arg, $opts)
169c84241d1Sespie{
170c84241d1Sespie
171c84241d1Sespie	my $canonical = ${$self->{alt}[0]};
172c84241d1Sespie	for my $s (@{$self->{alt}}) {
173c84241d1Sespie		if ($s->match($arg, $opts, $canonical, $self->{code})) {
174c84241d1Sespie			return 1;
175c84241d1Sespie		}
176c84241d1Sespie	}
177c84241d1Sespie	return 0;
178c84241d1Sespie}
179c84241d1Sespie
180c84241d1Sespie# seems I spend my life rewriting option handlers, not surprisingly...
181c84241d1Sespiepackage LT::Getopt;
182fc08f4fdSespieuse LT::Util;
183c84241d1Sespie
184c84241d1Sespie
185c84241d1Sespie# parsing an option 'all-static' will automatically add an
186c84241d1Sespie# accessor $self->all_static   that maps to the option.
187c84241d1Sespie
188*f41ccc36Sespiesub add_option_accessor($self, $option, $isarray)
189c84241d1Sespie{
190c84241d1Sespie	my $access = $option;
191c84241d1Sespie	$access =~ s/^\-//;
192c84241d1Sespie	$access =~ s/-/_/g;
193204852a3Sespie	my $actual = $isarray ?
194*f41ccc36Sespie		sub($self) {
195d38c979aSespie		    $self->{opt}{$option} //= [];
1960fa141abSespie		    if (wantarray) {
197204852a3Sespie			    return @{$self->{opt}{$option}};
1980fa141abSespie		    } else {
1990fa141abSespie			    return scalar @{$self->{opt}{$option}};
2000fa141abSespie		    }
201*f41ccc36Sespie		} : sub($self) {
202c84241d1Sespie		    return $self->{opt}{$option};
203c84241d1Sespie		};
204c84241d1Sespie	my $callpkg = ref($self);
205c84241d1Sespie	unless ($self->can($access)) {
206c84241d1Sespie		no strict 'refs';
207c84241d1Sespie		*{$callpkg."::$access"} = $actual;
208c84241d1Sespie	}
209c84241d1Sespie}
210c84241d1Sespie
211*f41ccc36Sespiesub create_options($self, @l)
212c84241d1Sespie{
213c84241d1Sespie	my @options = ();
214c84241d1Sespie	# first pass creates accessors
21551d2374bSzhuk	push(@l, '-tag=', sub { $self->add_tag($_[2]); });
216c84241d1Sespie	while (my $opt = shift @l) {
217204852a3Sespie		my $isarray = ($opt =~ s/\@$//);
218c84241d1Sespie		# default code or not
219c84241d1Sespie		my $code;
220c84241d1Sespie		if (@l > 0 && ref($l[0]) eq 'CODE') {
221c84241d1Sespie			$code = shift @l;
222c84241d1Sespie		} else {
223204852a3Sespie			if ($isarray) {
224c84241d1Sespie				$code = sub {
225c84241d1Sespie				    my ($object, $canonical, $value) = @_;
226c84241d1Sespie				    push(@{$object->{opt}{$canonical}}, $value);
227c84241d1Sespie				};
228c84241d1Sespie			} else {
229c84241d1Sespie				$code = sub {
230c84241d1Sespie				    my ($object, $canonical, $value) = @_;
231c84241d1Sespie				    $object->{opt}{$canonical} = $value;
232c84241d1Sespie				};
233c84241d1Sespie			}
234c84241d1Sespie		}
235*f41ccc36Sespie		push(@options,
236*f41ccc36Sespie		    Options->new($opt, $code)->setup($self, $isarray));
237c84241d1Sespie	}
23869325921Sespie	return @options;
23969325921Sespie}
24069325921Sespie
241*f41ccc36Sespiesub handle_options($self, @l)
24269325921Sespie{
24369325921Sespie	my @options = $self->create_options(@l);
244c84241d1Sespie
245c84241d1SespieMAINLOOP:
246c84241d1Sespie	while (@main::ARGV > 0) {
24728252c27Safresh1		my $arg = shift @main::ARGV;
24828252c27Safresh1		if ($arg =~ m/^\-\-$/) {
249c84241d1Sespie			last;
250c84241d1Sespie		}
25128252c27Safresh1		if ($arg =~ m/^\-/) {
252c84241d1Sespie			for my $opt (@options) {
25328252c27Safresh1				if ($opt->match($arg, $self)) {
254c84241d1Sespie					next MAINLOOP;
255c84241d1Sespie				}
256c84241d1Sespie			}
25728252c27Safresh1			shortdie "Unknown option $arg\n";
258c84241d1Sespie		} else {
25928252c27Safresh1			unshift(@main::ARGV, $arg);
260d5a610c6Sespie			last;
261c84241d1Sespie		}
262c84241d1Sespie	}
263c84241d1Sespie}
264c84241d1Sespie
265*f41ccc36Sespiesub handle_permuted_options($self, @l)
26669325921Sespie{
26769325921Sespie	my @options = $self->create_options(@l);
26869325921Sespie
26992d5e529Sespie	$self->{kept} = [];
27092d5e529Sespie
27169325921SespieMAINLOOP2:
27269325921Sespie	while (@main::ARGV > 0) {
27328252c27Safresh1		my $arg = shift @main::ARGV;
27428252c27Safresh1		if ($arg =~ m/^\-\-$/) {
27569325921Sespie			next;   # XXX ?
27669325921Sespie		}
27728252c27Safresh1		if ($arg =~ m/^\-/) {
27869325921Sespie			for my $opt (@options) {
27928252c27Safresh1				if ($opt->match($arg, $self)) {
28069325921Sespie					next MAINLOOP2;
28169325921Sespie				}
28269325921Sespie			}
28369325921Sespie		}
28428252c27Safresh1		$self->keep_for_later($arg);
28569325921Sespie	}
28692d5e529Sespie	@main::ARGV = @{$self->{kept}};
28792d5e529Sespie}
28892d5e529Sespie
289*f41ccc36Sespiesub keep_for_later($self, @args)
29092d5e529Sespie{
29192d5e529Sespie	push(@{$self->{kept}}, @args);
29269325921Sespie}
29369325921Sespie
294*f41ccc36Sespiesub new($class)
295c84241d1Sespie{
296c84241d1Sespie	bless {}, $class;
297c84241d1Sespie}
298c84241d1Sespie
299c84241d1Sespie1;
300