line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package Astro::App::Satpass2; |
2
|
|
|
|
|
|
|
|
3
|
20
|
|
|
20
|
|
1969
|
use 5.008; |
|
20
|
|
|
|
|
74
|
|
4
|
|
|
|
|
|
|
|
5
|
20
|
|
|
20
|
|
112
|
use strict; |
|
20
|
|
|
|
|
42
|
|
|
20
|
|
|
|
|
385
|
|
6
|
20
|
|
|
20
|
|
90
|
use warnings; |
|
20
|
|
|
|
|
48
|
|
|
20
|
|
|
|
|
696
|
|
7
|
|
|
|
|
|
|
|
8
|
20
|
|
|
20
|
|
8806
|
use Astro::App::Satpass2::Locale qw{ __localize }; |
|
20
|
|
|
|
|
60
|
|
|
20
|
|
|
|
|
1182
|
|
9
|
20
|
|
|
20
|
|
8668
|
use Astro::App::Satpass2::Macro::Command; |
|
20
|
|
|
|
|
57
|
|
|
20
|
|
|
|
|
599
|
|
10
|
20
|
|
|
20
|
|
8460
|
use Astro::App::Satpass2::Macro::Code; |
|
20
|
|
|
|
|
66
|
|
|
20
|
|
|
|
|
613
|
|
11
|
20
|
|
|
20
|
|
9126
|
use Astro::App::Satpass2::ParseTime; |
|
20
|
|
|
|
|
67
|
|
|
20
|
|
|
|
|
1023
|
|
12
|
20
|
|
|
|
|
3907
|
use Astro::App::Satpass2::Utils qw{ |
13
|
|
|
|
|
|
|
:ref |
14
|
|
|
|
|
|
|
__arguments __legal_options |
15
|
|
|
|
|
|
|
expand_tilde find_package_pod |
16
|
|
|
|
|
|
|
has_method instance load_package |
17
|
|
|
|
|
|
|
my_dist_config quoter |
18
|
|
|
|
|
|
|
__parse_class_and_args |
19
|
20
|
|
|
20
|
|
154
|
}; |
|
20
|
|
|
|
|
44
|
|
20
|
|
|
|
|
|
|
|
21
|
20
|
|
|
20
|
|
18527
|
use Astro::Coord::ECI 0.077; # This needs at least 0.049. |
|
20
|
|
|
|
|
269969
|
|
|
20
|
|
|
|
|
819
|
|
22
|
20
|
|
|
20
|
|
10509
|
use Astro::Coord::ECI::Moon 0.077; |
|
20
|
|
|
|
|
120163
|
|
|
20
|
|
|
|
|
792
|
|
23
|
20
|
|
|
20
|
|
9723
|
use Astro::Coord::ECI::Star 0.077; |
|
20
|
|
|
|
|
176234
|
|
|
20
|
|
|
|
|
869
|
|
24
|
20
|
|
|
20
|
|
10339
|
use Astro::Coord::ECI::Sun 0.077; |
|
20
|
|
|
|
|
74053
|
|
|
20
|
|
|
|
|
795
|
|
25
|
20
|
|
|
20
|
|
29680
|
use Astro::Coord::ECI::TLE 0.077 qw{:constants}; # This needs at least 0.059. |
|
20
|
|
|
|
|
1100261
|
|
|
20
|
|
|
|
|
5189
|
|
26
|
20
|
|
|
20
|
|
12650
|
use Astro::Coord::ECI::TLE::Set 0.077; |
|
20
|
|
|
|
|
54535
|
|
|
20
|
|
|
|
|
835
|
|
27
|
|
|
|
|
|
|
# The following includes @CARP_NOT. |
28
|
20
|
|
|
20
|
|
146
|
use Astro::Coord::ECI::Utils 0.112 qw{ :all }; # This needs at least 0.112. |
|
20
|
|
|
|
|
720
|
|
|
20
|
|
|
|
|
9583
|
|
29
|
|
|
|
|
|
|
|
30
|
|
|
|
|
|
|
{ |
31
|
|
|
|
|
|
|
local $@ = undef; |
32
|
20
|
|
50
|
|
|
43
|
use constant HAVE_TLE_IRIDIUM => eval { |
33
|
|
|
|
|
|
|
require Astro::Coord::ECI::TLE::Iridium; |
34
|
|
|
|
|
|
|
Astro::Coord::ECI::TLE::Iridium->VERSION( 0.077 ); |
35
|
|
|
|
|
|
|
1; |
36
|
20
|
|
|
20
|
|
166
|
} || 0; |
|
20
|
|
|
|
|
90
|
|
37
|
|
|
|
|
|
|
# Unfortunately the alias code creates the alias even if the version |
38
|
|
|
|
|
|
|
# is unacceptable; so we may have to just delete the Iridium aliases |
39
|
|
|
|
|
|
|
unless( HAVE_TLE_IRIDIUM ) { |
40
|
|
|
|
|
|
|
my %type_map = Astro::Coord::ECI::TLE->alias(); |
41
|
|
|
|
|
|
|
foreach my $name ( keys %type_map ) { |
42
|
|
|
|
|
|
|
$type_map{$name} eq 'Astro::Coord::ECI::TLE::Iridium' |
43
|
|
|
|
|
|
|
and Astro::Coord::ECI::TLE->alias( $name, undef ); |
44
|
|
|
|
|
|
|
} |
45
|
|
|
|
|
|
|
} |
46
|
|
|
|
|
|
|
} |
47
|
|
|
|
|
|
|
|
48
|
20
|
|
|
20
|
|
11860
|
use Attribute::Handlers; |
|
20
|
|
|
|
|
98396
|
|
|
20
|
|
|
|
|
142
|
|
49
|
20
|
|
|
20
|
|
711
|
use Clone (); |
|
20
|
|
|
|
|
48
|
|
|
20
|
|
|
|
|
284
|
|
50
|
20
|
|
|
20
|
|
123
|
use Cwd (); |
|
20
|
|
|
|
|
43
|
|
|
20
|
|
|
|
|
389
|
|
51
|
20
|
|
|
20
|
|
108
|
use File::Glob qw{ :glob }; |
|
20
|
|
|
|
|
44
|
|
|
20
|
|
|
|
|
4670
|
|
52
|
20
|
|
|
20
|
|
166
|
use File::HomeDir; |
|
20
|
|
|
|
|
41
|
|
|
20
|
|
|
|
|
1143
|
|
53
|
20
|
|
|
20
|
|
130
|
use File::Spec; |
|
20
|
|
|
|
|
51
|
|
|
20
|
|
|
|
|
642
|
|
54
|
20
|
|
|
20
|
|
16271
|
use File::Temp; |
|
20
|
|
|
|
|
218753
|
|
|
20
|
|
|
|
|
1514
|
|
55
|
20
|
|
|
20
|
|
167
|
use Getopt::Long 2.33; |
|
20
|
|
|
|
|
273
|
|
|
20
|
|
|
|
|
658
|
|
56
|
20
|
|
|
20
|
|
2561
|
use IO::File 1.14; |
|
20
|
|
|
|
|
450
|
|
|
20
|
|
|
|
|
2781
|
|
57
|
20
|
|
|
20
|
|
142
|
use IO::Handle; |
|
20
|
|
|
|
|
45
|
|
|
20
|
|
|
|
|
721
|
|
58
|
20
|
|
|
20
|
|
161
|
use POSIX qw{ floor }; |
|
20
|
|
|
|
|
91
|
|
|
20
|
|
|
|
|
177
|
|
59
|
20
|
|
|
20
|
|
1530
|
use Scalar::Util 1.26 qw{ blessed isdual openhandle }; |
|
20
|
|
|
|
|
420
|
|
|
20
|
|
|
|
|
1050
|
|
60
|
20
|
|
|
20
|
|
13726
|
use Text::Abbrev; |
|
20
|
|
|
|
|
926
|
|
|
20
|
|
|
|
|
1036
|
|
61
|
20
|
|
|
20
|
|
143
|
use Text::ParseWords (); # Used only for {level1} stuff. |
|
20
|
|
|
|
|
43
|
|
|
20
|
|
|
|
|
411
|
|
62
|
|
|
|
|
|
|
|
63
|
20
|
|
|
20
|
|
100
|
use constant ASTRO_SPACETRACK_VERSION => 0.105; |
|
20
|
|
|
|
|
43
|
|
|
20
|
|
|
|
|
1188
|
|
64
|
20
|
|
|
20
|
|
134
|
use constant DEFAULT_STDOUT_LAYERS => ':encoding(utf-8)'; |
|
20
|
|
|
|
|
46
|
|
|
20
|
|
|
|
|
1740
|
|
65
|
|
|
|
|
|
|
|
66
|
|
|
|
|
|
|
BEGIN { |
67
|
|
|
|
|
|
|
eval { |
68
|
20
|
50
|
|
|
|
175
|
load_package( 'Time::y2038' ) |
69
|
|
|
|
|
|
|
and Time::y2038->import(); |
70
|
20
|
|
|
|
|
1199
|
1; |
71
|
|
|
|
|
|
|
} |
72
|
20
|
50
|
|
20
|
|
90
|
or do { |
73
|
0
|
|
|
|
|
0
|
require Time::Local; |
74
|
0
|
|
|
|
|
0
|
Time::Local->import(); |
75
|
|
|
|
|
|
|
}; |
76
|
|
|
|
|
|
|
} |
77
|
|
|
|
|
|
|
|
78
|
|
|
|
|
|
|
# The following is returned by method _attribute_value() when a |
79
|
|
|
|
|
|
|
# non-existent attribute is specified. We can't use undef for this, |
80
|
|
|
|
|
|
|
# because the attribute might really be undef. |
81
|
|
|
|
|
|
|
# NOTE that this used to be just bless \( $x = undef ) ..., but blead |
82
|
|
|
|
|
|
|
# Perl 6a011f13d7690dbe2e03ad7500756c983bcb1834 did not like this |
83
|
|
|
|
|
|
|
# (modificatoin of read-only variable). |
84
|
20
|
|
|
|
|
59
|
use constant NULL => do { |
85
|
20
|
|
|
|
|
67
|
my $x = undef; |
86
|
20
|
|
|
|
|
1617
|
bless \$x, 'Null'; |
87
|
20
|
|
|
20
|
|
148
|
}; |
|
20
|
|
|
|
|
50
|
|
88
|
|
|
|
|
|
|
# The canonical way to see if $rslt actually contains the above is |
89
|
|
|
|
|
|
|
# NULL_REF eq ref $rslt |
90
|
20
|
|
|
20
|
|
134
|
use constant NULL_REF => ref NULL; |
|
20
|
|
|
|
|
46
|
|
|
20
|
|
|
|
|
1069
|
|
91
|
|
|
|
|
|
|
|
92
|
20
|
|
|
20
|
|
119
|
use constant SUN_CLASS_DEFAULT => 'Astro::Coord::ECI::Sun'; |
|
20
|
|
|
|
|
45
|
|
|
20
|
|
|
|
|
8817
|
|
93
|
|
|
|
|
|
|
|
94
|
|
|
|
|
|
|
our $VERSION = '0.051_01'; |
95
|
|
|
|
|
|
|
|
96
|
|
|
|
|
|
|
# The following 'cute' code is so that we do not determine whether we |
97
|
|
|
|
|
|
|
# actually have optional modules until we really need them, and yet do |
98
|
|
|
|
|
|
|
# not repeat the process once it is done. |
99
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
my $have_time_hires; |
101
|
|
|
|
|
|
|
$have_time_hires = sub { |
102
|
|
|
|
|
|
|
my $value = load_package( 'Time::HiRes' ); |
103
|
|
|
|
|
|
|
$have_time_hires = sub { return $value }; |
104
|
|
|
|
|
|
|
return $value; |
105
|
|
|
|
|
|
|
}; |
106
|
|
|
|
|
|
|
|
107
|
|
|
|
|
|
|
my $have_astro_spacetrack; |
108
|
|
|
|
|
|
|
$have_astro_spacetrack = sub { |
109
|
|
|
|
|
|
|
my $value = load_package( { lib => undef }, 'Astro::SpaceTrack' ) && eval { |
110
|
|
|
|
|
|
|
Astro::SpaceTrack->VERSION( ASTRO_SPACETRACK_VERSION ); |
111
|
|
|
|
|
|
|
1; |
112
|
|
|
|
|
|
|
}; |
113
|
|
|
|
|
|
|
$have_astro_spacetrack = sub { $value }; |
114
|
|
|
|
|
|
|
return $value; |
115
|
|
|
|
|
|
|
}; |
116
|
|
|
|
|
|
|
|
117
|
|
|
|
|
|
|
my $default_geocoder; |
118
|
|
|
|
|
|
|
$default_geocoder = sub { |
119
|
|
|
|
|
|
|
my $value = |
120
|
|
|
|
|
|
|
_can_use_geocoder( 'Astro::App::Satpass2::Geocode::OSM' |
121
|
|
|
|
|
|
|
); |
122
|
|
|
|
|
|
|
$default_geocoder = sub { return $value }; |
123
|
|
|
|
|
|
|
return $value; |
124
|
|
|
|
|
|
|
}; |
125
|
|
|
|
|
|
|
|
126
|
|
|
|
|
|
|
sub _can_use_geocoder { |
127
|
0
|
|
|
0
|
|
0
|
my ( $geocoder ) = @_; |
128
|
0
|
0
|
|
|
|
0
|
my $pkg = load_package( $geocoder ) |
129
|
|
|
|
|
|
|
or return; |
130
|
0
|
0
|
|
|
|
0
|
load_package( $pkg->GEOCODER_CLASS() ) |
131
|
|
|
|
|
|
|
or return; |
132
|
0
|
|
|
|
|
0
|
return $pkg; |
133
|
|
|
|
|
|
|
} |
134
|
|
|
|
|
|
|
|
135
|
|
|
|
|
|
|
my $interrupted = 'Interrupted by user.'; |
136
|
|
|
|
|
|
|
|
137
|
|
|
|
|
|
|
my %twilight_def = ( |
138
|
|
|
|
|
|
|
civil => deg2rad (-6), |
139
|
|
|
|
|
|
|
nautical => deg2rad (-12), |
140
|
|
|
|
|
|
|
astronomical => deg2rad (-18), |
141
|
|
|
|
|
|
|
); |
142
|
|
|
|
|
|
|
my %twilight_abbr = abbrev (keys %twilight_def); |
143
|
|
|
|
|
|
|
|
144
|
|
|
|
|
|
|
# Individual commands are defined by subroutines of the same name, |
145
|
|
|
|
|
|
|
# and having the Verb attribute. You can specify additional |
146
|
|
|
|
|
|
|
# attributes if you need to. Following are descriptions of the |
147
|
|
|
|
|
|
|
# attributes used by this script. |
148
|
|
|
|
|
|
|
# |
149
|
|
|
|
|
|
|
# Configure(configurations) |
150
|
|
|
|
|
|
|
# |
151
|
|
|
|
|
|
|
# The 'Configure' attribute specifies options to be passed to |
152
|
|
|
|
|
|
|
# Getopt::Long::Configure before the options are parsed. For |
153
|
|
|
|
|
|
|
# example, if a command wants to keep unrecognized options on the |
154
|
|
|
|
|
|
|
# command you would specify: |
155
|
|
|
|
|
|
|
# sub foo : Configure(pass_through) Verb |
156
|
|
|
|
|
|
|
# |
157
|
|
|
|
|
|
|
# Tokenize(options) |
158
|
|
|
|
|
|
|
# |
159
|
|
|
|
|
|
|
# The 'Tokenize' attribute specifies tokenizatino options. These |
160
|
|
|
|
|
|
|
# can not take effect until fairly late in the parse when the |
161
|
|
|
|
|
|
|
# tokens are known. These options are parsed by Getopt::Long, and |
162
|
|
|
|
|
|
|
# the value of the attribute is a reference to the options hash |
163
|
|
|
|
|
|
|
# thus generated. Possible options are: |
164
|
|
|
|
|
|
|
# -expand_tilde - Expand tildes in the tokens. For historical |
165
|
|
|
|
|
|
|
# reasons this is the default, but it can be negated by |
166
|
|
|
|
|
|
|
# specifying -noexpand_tilde. Tildes in redirect |
167
|
|
|
|
|
|
|
# specifications are always expanded. |
168
|
|
|
|
|
|
|
# |
169
|
|
|
|
|
|
|
# Tweak(options) |
170
|
|
|
|
|
|
|
# |
171
|
|
|
|
|
|
|
# The 'Tweak' attribute specifies miscellaneous tweaks to |
172
|
|
|
|
|
|
|
# subroutine usage. Possible options are: |
173
|
|
|
|
|
|
|
# -unsatisfied - Execute even inside an unsatisfied if(). |
174
|
|
|
|
|
|
|
# Subroutines with this attribute may have to be aware |
175
|
|
|
|
|
|
|
# that they are being called within the scope of an |
176
|
|
|
|
|
|
|
# unsatisfied if(). All interactive methods that must be |
177
|
|
|
|
|
|
|
# called even inside an unsatisfied if() MUST have this |
178
|
|
|
|
|
|
|
# attribute. These are begin() and end(), and anything |
179
|
|
|
|
|
|
|
# that might dispatch either of these. At the moment this |
180
|
|
|
|
|
|
|
# means if() and time(). |
181
|
|
|
|
|
|
|
# -completion - Requires as argument the name of the command |
182
|
|
|
|
|
|
|
# completion method. This can not be checked at compile |
183
|
|
|
|
|
|
|
# time. It will be called with the following arguments: |
184
|
|
|
|
|
|
|
# $code - the relevant code reference |
185
|
|
|
|
|
|
|
# $text - the text being completed |
186
|
|
|
|
|
|
|
# $line - the line being completed |
187
|
|
|
|
|
|
|
# $start - the current position in the line. |
188
|
|
|
|
|
|
|
# It should return either a reference to an array |
189
|
|
|
|
|
|
|
# containing possible completions, or nothing to fall |
190
|
|
|
|
|
|
|
# through to standard completion |
191
|
|
|
|
|
|
|
# |
192
|
|
|
|
|
|
|
# Verb(options) |
193
|
|
|
|
|
|
|
# |
194
|
|
|
|
|
|
|
# The 'Verb' attribute identifies the subroutine as representing a |
195
|
|
|
|
|
|
|
# cvsx command. If it has options, they should be specified inside |
196
|
|
|
|
|
|
|
# parentheses as a whitespace-separated list of option |
197
|
|
|
|
|
|
|
# specifications appropriate for Getopt::Long. For example: |
198
|
|
|
|
|
|
|
# sub foo : Verb(bar baz=s) |
199
|
|
|
|
|
|
|
# specifies that 'foo' is a command, taking options -bar, and |
200
|
|
|
|
|
|
|
# -baz; the latter takes a string value. |
201
|
|
|
|
|
|
|
|
202
|
|
|
|
|
|
|
{ |
203
|
|
|
|
|
|
|
my %attr; |
204
|
|
|
|
|
|
|
|
205
|
|
|
|
|
|
|
sub Configure : ATTR(CODE,RAWDATA) { |
206
|
0
|
|
|
0
|
0
|
0
|
my ( undef, undef, $code, $name, $data ) = @_; |
207
|
0
|
|
|
|
|
0
|
$attr{$code}{$name} = _attr_list( $data ); |
208
|
0
|
|
|
|
|
0
|
return; |
209
|
20
|
|
|
20
|
|
196
|
} |
|
20
|
|
|
|
|
66
|
|
|
20
|
|
|
|
|
147
|
|
210
|
|
|
|
|
|
|
|
211
|
|
|
|
|
|
|
sub Tokenize : ATTR(CODE,RAWDATA) { |
212
|
19
|
|
|
19
|
0
|
29237
|
my ( undef, undef, $code, $name, $data ) = @_; |
213
|
19
|
|
|
|
|
129
|
my $opt = _attr_hash( $name, $data, qw{ expand_tilde|expand-tilde! } ); |
214
|
|
|
|
|
|
|
exists $opt->{expand_tilde} |
215
|
19
|
50
|
|
|
|
133
|
or $opt->{expand_tilde} = 1; |
216
|
19
|
|
|
|
|
103
|
$attr{$code}{$name} = $opt; |
217
|
19
|
|
|
|
|
72
|
return; |
218
|
20
|
|
|
20
|
|
21926
|
} |
|
20
|
|
|
|
|
81
|
|
|
20
|
|
|
|
|
84
|
|
219
|
|
|
|
|
|
|
|
220
|
|
|
|
|
|
|
sub Tweak : ATTR(CODE,RAWDATA) { |
221
|
266
|
|
|
266
|
0
|
7468
|
my ( undef, undef, $code, $name, $data ) = @_; |
222
|
266
|
|
|
|
|
643
|
$attr{$code}{$name} = _attr_hash( $name, $data, |
223
|
|
|
|
|
|
|
qw{ completion=s unsatisfied! } ); |
224
|
266
|
|
|
|
|
780
|
return; |
225
|
20
|
|
|
20
|
|
22018
|
} |
|
20
|
|
|
|
|
65
|
|
|
20
|
|
|
|
|
94
|
|
226
|
|
|
|
|
|
|
|
227
|
|
|
|
|
|
|
sub Verb : ATTR(CODE,RAWDATA) { |
228
|
1239
|
|
|
1239
|
0
|
2204841
|
my ( undef, undef, $code, $name, $data ) = @_; |
229
|
1239
|
|
|
|
|
2635
|
$attr{$code}{$name} = _attr_list( $data ); |
230
|
1239
|
|
|
|
|
3492
|
return; |
231
|
20
|
|
|
20
|
|
19663
|
} |
|
20
|
|
|
|
|
88
|
|
|
20
|
|
|
|
|
103
|
|
232
|
|
|
|
|
|
|
|
233
|
|
|
|
|
|
|
sub _attr_hash { |
234
|
285
|
|
|
285
|
|
714
|
my ( $name, $arg, @legal ) = @_; |
235
|
285
|
|
|
|
|
1017
|
my $gol = Getopt::Long::Parser->new(); |
236
|
285
|
|
|
|
|
5077
|
my %opt; |
237
|
|
|
|
|
|
|
$gol->getoptionsfromarray( |
238
|
|
|
|
|
|
|
_attr_list( $arg ), |
239
|
|
|
|
|
|
|
\%opt, |
240
|
|
|
|
|
|
|
@legal, |
241
|
285
|
50
|
|
|
|
572
|
) or do { |
242
|
0
|
|
|
|
|
0
|
require Carp; |
243
|
0
|
|
|
|
|
0
|
Carp::croak( "Bad $name option" ); |
244
|
|
|
|
|
|
|
}; |
245
|
285
|
|
|
|
|
93763
|
return \%opt; |
246
|
|
|
|
|
|
|
} |
247
|
|
|
|
|
|
|
|
248
|
|
|
|
|
|
|
sub _attr_list { |
249
|
1524
|
50
|
|
1524
|
|
4223
|
defined( local $_ = $_[0] ) |
250
|
|
|
|
|
|
|
or return []; |
251
|
1524
|
|
|
|
|
5353
|
s/ \A \s+ //smx; |
252
|
1524
|
|
|
|
|
15270
|
return [ split qr< \s+ >smx ]; |
253
|
|
|
|
|
|
|
} |
254
|
|
|
|
|
|
|
|
255
|
|
|
|
|
|
|
sub __get_attr { |
256
|
1235
|
|
|
1235
|
|
2724
|
my ( undef, $code, $name, $dflt ) = @_; # $pkg unused |
257
|
1235
|
50
|
|
|
|
2527
|
defined $code |
258
|
|
|
|
|
|
|
or return \%attr; |
259
|
|
|
|
|
|
|
defined $name |
260
|
1235
|
50
|
|
|
|
2290
|
or return $attr{$code}; |
261
|
|
|
|
|
|
|
exists $attr{$code}{$name} |
262
|
1235
|
100
|
|
|
|
5566
|
and return $attr{$code}{$name}; |
263
|
628
|
|
|
|
|
2389
|
return $dflt; |
264
|
|
|
|
|
|
|
} |
265
|
|
|
|
|
|
|
} |
266
|
|
|
|
|
|
|
|
267
|
|
|
|
|
|
|
my %mutator = ( |
268
|
|
|
|
|
|
|
almanac_horizon => \&_set_almanac_horizon, |
269
|
|
|
|
|
|
|
appulse => \&_set_angle, |
270
|
|
|
|
|
|
|
autoheight => \&_set_unmodified, |
271
|
|
|
|
|
|
|
backdate => \&_set_unmodified, |
272
|
|
|
|
|
|
|
background => \&_set_unmodified, |
273
|
|
|
|
|
|
|
continuation_prompt => \&_set_unmodified, |
274
|
|
|
|
|
|
|
country => \&_set_unmodified, |
275
|
|
|
|
|
|
|
date_format => \&_set_formatter_attribute, |
276
|
|
|
|
|
|
|
desired_equinox_dynamical => \&_set_formatter_attribute, |
277
|
|
|
|
|
|
|
debug => \&_set_unmodified, |
278
|
|
|
|
|
|
|
echo => \&_set_unmodified, |
279
|
|
|
|
|
|
|
edge_of_earths_shadow => \&_set_unmodified, |
280
|
|
|
|
|
|
|
ellipsoid => \&_set_ellipsoid, |
281
|
|
|
|
|
|
|
error_out => \&_set_unmodified, |
282
|
|
|
|
|
|
|
events => \&_set_unmodified, |
283
|
|
|
|
|
|
|
exact_event => \&_set_unmodified, |
284
|
|
|
|
|
|
|
execute_filter => \&_set_code_ref, # Undocumented and unsupported |
285
|
|
|
|
|
|
|
explicit_macro_delete => \&_set_unmodified, |
286
|
|
|
|
|
|
|
extinction => \&_set_unmodified, |
287
|
|
|
|
|
|
|
filter => \&_set_unmodified, |
288
|
|
|
|
|
|
|
flare_mag_day => \&_set_unmodified, |
289
|
|
|
|
|
|
|
flare_mag_night => \&_set_unmodified, |
290
|
|
|
|
|
|
|
formatter => \&_set_formatter, |
291
|
|
|
|
|
|
|
geocoder => \&_set_geocoder, |
292
|
|
|
|
|
|
|
geometric => \&_set_unmodified, |
293
|
|
|
|
|
|
|
gmt => \&_set_formatter_attribute, |
294
|
|
|
|
|
|
|
height => \&_set_distance_meters, |
295
|
|
|
|
|
|
|
horizon => \&_set_angle, |
296
|
|
|
|
|
|
|
illum => \&_set_illum_class, |
297
|
|
|
|
|
|
|
latitude => \&_set_angle_or_undef, |
298
|
|
|
|
|
|
|
local_coord => \&_set_formatter_attribute, |
299
|
|
|
|
|
|
|
location => \&_set_unmodified, |
300
|
|
|
|
|
|
|
longitude => \&_set_angle_or_undef, |
301
|
|
|
|
|
|
|
model => \&_set_model, |
302
|
|
|
|
|
|
|
max_mirror_angle => \&_set_angle, |
303
|
|
|
|
|
|
|
output_layers => \&_set_output_layers, |
304
|
|
|
|
|
|
|
pass_threshold => \&_set_angle_or_undef, |
305
|
|
|
|
|
|
|
pass_variant => \&_set_pass_variant, |
306
|
|
|
|
|
|
|
perltime => \&_set_time_parser_attribute, |
307
|
|
|
|
|
|
|
prompt => \&_set_unmodified, |
308
|
|
|
|
|
|
|
refraction => \&_set_unmodified, |
309
|
|
|
|
|
|
|
simbad_url => \&_set_unmodified, |
310
|
|
|
|
|
|
|
singleton => \&_set_unmodified, |
311
|
|
|
|
|
|
|
spacetrack => \&_set_spacetrack, |
312
|
|
|
|
|
|
|
stdout => \&_set_stdout, |
313
|
|
|
|
|
|
|
sun => \&_set_sun_class, # Only in {level1} |
314
|
|
|
|
|
|
|
time_format => \&_set_formatter_attribute, |
315
|
|
|
|
|
|
|
time_formatter => \&_set_formatter_attribute, |
316
|
|
|
|
|
|
|
time_parser => \&_set_time_parser, |
317
|
|
|
|
|
|
|
## timing => \&_set_unmodified, |
318
|
|
|
|
|
|
|
twilight => \&_set_twilight, # 'civil', 'nautical', 'astronomical' |
319
|
|
|
|
|
|
|
# (or a unique abbreviation thereof), |
320
|
|
|
|
|
|
|
# or degrees above (positive) or below |
321
|
|
|
|
|
|
|
# (negative) the geometric horizon. |
322
|
|
|
|
|
|
|
tz => \&_set_tz, |
323
|
|
|
|
|
|
|
verbose => \&_set_unmodified, # 0 = events only |
324
|
|
|
|
|
|
|
# 1 = whenever above horizon |
325
|
|
|
|
|
|
|
# 2 = anytime |
326
|
|
|
|
|
|
|
visible => \&_set_unmodified, # 1 = only if sun down & sat illuminated |
327
|
|
|
|
|
|
|
warning => \&_set_warner_attribute, # True to warn/die; false to carp/croak. |
328
|
|
|
|
|
|
|
warn_on_empty => \&_set_unmodified, |
329
|
|
|
|
|
|
|
# True to have list commands warn on |
330
|
|
|
|
|
|
|
# an empty list. |
331
|
|
|
|
|
|
|
webcmd => \&_set_webcmd, # Command to spawn for web pages |
332
|
|
|
|
|
|
|
); |
333
|
|
|
|
|
|
|
|
334
|
|
|
|
|
|
|
my %accessor = ( |
335
|
|
|
|
|
|
|
date_format => \&_get_formatter_attribute, |
336
|
|
|
|
|
|
|
desired_equinox_dynamical => \&_get_formatter_attribute, |
337
|
|
|
|
|
|
|
geocoder => \&_get_geocoder, |
338
|
|
|
|
|
|
|
gmt => \&_get_formatter_attribute, |
339
|
|
|
|
|
|
|
local_coord => \&_get_formatter_attribute, |
340
|
|
|
|
|
|
|
perltime => \&_get_time_parser_attribute, |
341
|
|
|
|
|
|
|
spacetrack => \&_get_spacetrack, |
342
|
|
|
|
|
|
|
time_format => \&_get_formatter_attribute, |
343
|
|
|
|
|
|
|
time_formatter => \&_get_formatter_attribute, |
344
|
|
|
|
|
|
|
tz => \&_get_time_parser_attribute, |
345
|
|
|
|
|
|
|
warning => \&_get_warner_attribute, |
346
|
|
|
|
|
|
|
); |
347
|
|
|
|
|
|
|
|
348
|
|
|
|
|
|
|
foreach ( keys %mutator, qw{ initfile } ) { |
349
|
|
|
|
|
|
|
$accessor{$_} ||= sub { return $_[0]->{$_[1]} }; |
350
|
|
|
|
|
|
|
} |
351
|
|
|
|
|
|
|
|
352
|
|
|
|
|
|
|
my %shower = ( |
353
|
|
|
|
|
|
|
date_format => \&_show_formatter_attribute, |
354
|
|
|
|
|
|
|
desired_equinox_dynamical => \&_show_formatter_attribute, |
355
|
|
|
|
|
|
|
formatter => \&_show_copyable, |
356
|
|
|
|
|
|
|
geocoder => \&_show_copyable, |
357
|
|
|
|
|
|
|
gmt => \&_show_formatter_attribute, |
358
|
|
|
|
|
|
|
local_coord => \&_show_formatter_attribute, |
359
|
|
|
|
|
|
|
pass_variant => \&_show_pass_variant, |
360
|
|
|
|
|
|
|
sun => \&_show_sun_class, # only in {level1} |
361
|
|
|
|
|
|
|
time_parser => \&_show_time_parser, |
362
|
|
|
|
|
|
|
time_format => \&_show_formatter_attribute, |
363
|
|
|
|
|
|
|
time_formatter => \&_show_formatter_attribute, |
364
|
|
|
|
|
|
|
); |
365
|
|
|
|
|
|
|
foreach ( keys %accessor ) { $shower{$_} ||= \&_show_unmodified } |
366
|
|
|
|
|
|
|
|
367
|
|
|
|
|
|
|
# Attributes which must be set programmatically (i.e. not |
368
|
|
|
|
|
|
|
# interactively or in the initialization file). |
369
|
|
|
|
|
|
|
|
370
|
|
|
|
|
|
|
my %nointeractive = map {$_ => 1} qw{ |
371
|
|
|
|
|
|
|
execute_filter |
372
|
|
|
|
|
|
|
spacetrack |
373
|
|
|
|
|
|
|
stdout |
374
|
|
|
|
|
|
|
}; |
375
|
|
|
|
|
|
|
|
376
|
|
|
|
|
|
|
# Initial object contents |
377
|
|
|
|
|
|
|
|
378
|
|
|
|
|
|
|
my %static = ( |
379
|
|
|
|
|
|
|
almanac_horizon => 0, |
380
|
|
|
|
|
|
|
appulse => 0, |
381
|
|
|
|
|
|
|
autoheight => 1, |
382
|
|
|
|
|
|
|
background => 1, |
383
|
|
|
|
|
|
|
backdate => 0, |
384
|
|
|
|
|
|
|
continuation_prompt => '> ', |
385
|
|
|
|
|
|
|
date_format => '%a %d-%b-%Y', |
386
|
|
|
|
|
|
|
debug => 0, |
387
|
|
|
|
|
|
|
echo => 0, |
388
|
|
|
|
|
|
|
edge_of_earths_shadow => 1, |
389
|
|
|
|
|
|
|
ellipsoid => Astro::Coord::ECI->get ('ellipsoid'), |
390
|
|
|
|
|
|
|
error_out => 0, |
391
|
|
|
|
|
|
|
events => 0, |
392
|
|
|
|
|
|
|
exact_event => 1, |
393
|
|
|
|
|
|
|
execute_filter => sub { return 1 }, # Undocumented and unsupported |
394
|
|
|
|
|
|
|
## explicit_macro_delete => 1, # Deprecated |
395
|
|
|
|
|
|
|
extinction => 1, |
396
|
|
|
|
|
|
|
filter => 0, |
397
|
|
|
|
|
|
|
flare_mag_day => -6, |
398
|
|
|
|
|
|
|
flare_mag_night => 0, |
399
|
|
|
|
|
|
|
formatter => 'Astro::App::Satpass2::Format::Template', # Formatter class. |
400
|
|
|
|
|
|
|
## geocoder => $default_geocoder->(), # Geocoder class set when accessed |
401
|
|
|
|
|
|
|
geometric => 1, |
402
|
|
|
|
|
|
|
height => undef, # meters |
403
|
|
|
|
|
|
|
# initfile => undef, # Set by init() |
404
|
|
|
|
|
|
|
horizon => 20, # degrees |
405
|
|
|
|
|
|
|
illum => SUN_CLASS_DEFAULT, |
406
|
|
|
|
|
|
|
latitude => undef, # degrees |
407
|
|
|
|
|
|
|
longitude => undef, # degrees |
408
|
|
|
|
|
|
|
max_mirror_angle => HAVE_TLE_IRIDIUM ? rad2deg( |
409
|
|
|
|
|
|
|
Astro::Coord::ECI::TLE::Iridium->DEFAULT_MAX_MIRROR_ANGLE ) : |
410
|
|
|
|
|
|
|
undef, |
411
|
|
|
|
|
|
|
model => 'model', |
412
|
|
|
|
|
|
|
# pending => undef, # Continued input line if it exists. |
413
|
|
|
|
|
|
|
pass_variant => PASS_VARIANT_NONE, |
414
|
|
|
|
|
|
|
perltime => 0, |
415
|
|
|
|
|
|
|
prompt => 'satpass2> ', |
416
|
|
|
|
|
|
|
refraction => 1, |
417
|
|
|
|
|
|
|
simbad_url => 'simbad.u-strasbg.fr', |
418
|
|
|
|
|
|
|
singleton => 0, |
419
|
|
|
|
|
|
|
# spacetrack => undef, # Astro::SpaceTrack object set when accessed |
420
|
|
|
|
|
|
|
# stdout => undef, # Set to stdout in new(). |
421
|
|
|
|
|
|
|
output_layers => DEFAULT_STDOUT_LAYERS, |
422
|
|
|
|
|
|
|
time_parser => 'Astro::App::Satpass2::ParseTime', # Time parser class. |
423
|
|
|
|
|
|
|
twilight => 'civil', |
424
|
|
|
|
|
|
|
tz => $ENV{TZ}, |
425
|
|
|
|
|
|
|
verbose => 0, |
426
|
|
|
|
|
|
|
visible => 1, |
427
|
|
|
|
|
|
|
warning => 0, |
428
|
|
|
|
|
|
|
warn_on_empty => 1, |
429
|
|
|
|
|
|
|
webcmd => '' |
430
|
|
|
|
|
|
|
); |
431
|
|
|
|
|
|
|
|
432
|
|
|
|
|
|
|
my %sky_class = ( |
433
|
|
|
|
|
|
|
fold_case( 'Sun' ) => [ SUN_CLASS_DEFAULT, name => 'Sun' ], |
434
|
|
|
|
|
|
|
fold_case( 'Moon' ) => [ 'Astro::Coord::ECI::Moon', name => 'Moon' ], |
435
|
|
|
|
|
|
|
# # The shape of things to come -- maybe |
436
|
|
|
|
|
|
|
# # but commented out because Astro-App-Satpass2 does not depend on |
437
|
|
|
|
|
|
|
# # these |
438
|
|
|
|
|
|
|
# ( map { fold_case( $_ ) => |
439
|
|
|
|
|
|
|
# "Astro::Coord::ECI::VSOP87D::$_" } qw{ Mercury Venus |
440
|
|
|
|
|
|
|
# Mars Jupiter Saturn Uranus Neptune } ), |
441
|
|
|
|
|
|
|
); |
442
|
|
|
|
|
|
|
|
443
|
|
|
|
|
|
|
sub new { |
444
|
7
|
|
|
7
|
1
|
6599
|
my ( $class, %args ) = @_; |
445
|
7
|
50
|
|
|
|
40
|
ref $class and $class = ref $class; |
446
|
7
|
|
|
|
|
22
|
my $self = {}; |
447
|
7
|
|
|
|
|
24
|
$self->{bodies} = []; |
448
|
7
|
|
|
|
|
26
|
$self->{macro} = {}; |
449
|
|
|
|
|
|
|
$self->{sky} = [ |
450
|
7
|
|
|
|
|
69
|
SUN_CLASS_DEFAULT->new (), |
451
|
|
|
|
|
|
|
Astro::Coord::ECI::Moon->new (), |
452
|
|
|
|
|
|
|
]; |
453
|
7
|
|
|
|
|
3028
|
$self->{sky_class} = { %sky_class }; |
454
|
|
|
|
|
|
|
$self->{_help_module} = { |
455
|
7
|
|
|
|
|
70
|
'' => __PACKAGE__, |
456
|
|
|
|
|
|
|
eci => 'Astro::Coord::ECI', |
457
|
|
|
|
|
|
|
moon => 'Astro::Coord::ECI::Moon', |
458
|
|
|
|
|
|
|
set => 'Astro::Coord::ECI::TLE::Set', |
459
|
|
|
|
|
|
|
sun => SUN_CLASS_DEFAULT, |
460
|
|
|
|
|
|
|
spacetrack => 'Astro::SpaceTrack', |
461
|
|
|
|
|
|
|
star => 'Astro::Coord::ECI::Star', |
462
|
|
|
|
|
|
|
tle => 'Astro::Coord::ECI::TLE', |
463
|
|
|
|
|
|
|
utils => 'Astro::Coord::ECI::Utils', |
464
|
|
|
|
|
|
|
}; |
465
|
|
|
|
|
|
|
HAVE_TLE_IRIDIUM |
466
|
7
|
|
|
|
|
17
|
and $self->{_help_module}{iridium} = 'Astro::Coord::ECI::TLE::Iridium'; |
467
|
7
|
|
|
|
|
19
|
bless $self, $class; |
468
|
7
|
|
|
|
|
39
|
$self->_frame_push(initial => []); |
469
|
7
|
|
|
|
|
52
|
$self->set(stdout => select()); |
470
|
|
|
|
|
|
|
|
471
|
7
|
|
|
|
|
99
|
foreach my $name ( keys %static ) { |
472
|
301
|
50
|
|
|
|
709
|
exists $args{$name} or $args{$name} = $static{$name}; |
473
|
|
|
|
|
|
|
} |
474
|
|
|
|
|
|
|
|
475
|
|
|
|
|
|
|
$self->{_warner} = Astro::App::Satpass2::Warner->new( |
476
|
|
|
|
|
|
|
warning => delete $args{warning} |
477
|
7
|
|
|
|
|
92
|
); |
478
|
|
|
|
|
|
|
|
479
|
7
|
|
|
|
|
27
|
foreach my $name ( qw{ formatter time_parser } ) { |
480
|
14
|
|
|
|
|
62
|
$self->set( $name => delete $args{$name} ); |
481
|
|
|
|
|
|
|
} |
482
|
|
|
|
|
|
|
|
483
|
7
|
|
|
|
|
136
|
$self->set( %args ); |
484
|
|
|
|
|
|
|
|
485
|
7
|
|
|
|
|
83
|
return $self; |
486
|
|
|
|
|
|
|
} |
487
|
|
|
|
|
|
|
|
488
|
|
|
|
|
|
|
sub add { |
489
|
1
|
|
|
1
|
1
|
32
|
my ( $self, @bodies ) = @_; |
490
|
1
|
|
|
|
|
21
|
foreach my $body ( @bodies ) { |
491
|
1
|
50
|
|
|
|
45
|
embodies( $body, 'Astro::Coord::ECI::TLE' ) |
492
|
|
|
|
|
|
|
or $self->wail( |
493
|
|
|
|
|
|
|
'Arguments must represent Astro::Coord::ECI::TLE objects' ); |
494
|
|
|
|
|
|
|
} |
495
|
1
|
|
|
|
|
59
|
push @{ $self->{bodies} }, @bodies; |
|
1
|
|
|
|
|
21
|
|
496
|
1
|
|
|
|
|
18
|
return $self; |
497
|
|
|
|
|
|
|
} |
498
|
|
|
|
|
|
|
|
499
|
|
|
|
|
|
|
sub alias : Verb() { |
500
|
5
|
|
|
5
|
1
|
17
|
my ( undef, undef, @args ) = __arguments( @_ ); # Invocant, $opt unused |
501
|
|
|
|
|
|
|
|
502
|
5
|
100
|
|
|
|
18
|
if ( @args ) { |
503
|
2
|
|
|
|
|
12
|
Astro::Coord::ECI::TLE->alias( @args ); |
504
|
2
|
|
|
|
|
52
|
return; |
505
|
|
|
|
|
|
|
} else { |
506
|
3
|
|
|
|
|
6
|
my $output; |
507
|
3
|
|
|
|
|
12
|
my %alias = Astro::Coord::ECI::TLE->alias(); |
508
|
3
|
|
|
|
|
47
|
foreach my $key ( sort keys %alias ) { |
509
|
10
|
|
|
|
|
31
|
$output .= join( ' ', 'alias', $key, $alias{$key} ) . "\n"; |
510
|
|
|
|
|
|
|
} |
511
|
3
|
|
|
|
|
12
|
return $output; |
512
|
|
|
|
|
|
|
} |
513
|
20
|
|
|
20
|
|
48598
|
} |
|
20
|
|
|
|
|
67
|
|
|
20
|
|
|
|
|
105
|
|
514
|
|
|
|
|
|
|
|
515
|
|
|
|
|
|
|
# Attributes must all be on one line to process correctly under Perl |
516
|
|
|
|
|
|
|
# 5.8.8. |
517
|
|
|
|
|
|
|
sub almanac : Verb( choose=s@ dump! horizon|rise|set! transit! twilight! quarter! ) { |
518
|
3
|
|
|
3
|
1
|
18
|
my ( $self, $opt, @args ) = __arguments( @_ ); |
519
|
3
|
|
|
|
|
27
|
$self->_apply_boolean_default( |
520
|
|
|
|
|
|
|
$opt, 0, qw{ horizon transit twilight quarter } ); |
521
|
|
|
|
|
|
|
|
522
|
3
|
|
|
|
|
26
|
my $almanac_start = $self->__parse_time( |
523
|
|
|
|
|
|
|
shift @args, $self->_get_day_midnight()); |
524
|
3
|
|
50
|
|
|
17
|
my $almanac_end = $self->__parse_time (shift @args || '+1'); |
525
|
|
|
|
|
|
|
|
526
|
3
|
50
|
|
|
|
18
|
$almanac_start >= $almanac_end |
527
|
|
|
|
|
|
|
and $self->wail( 'End time must be after start time' ); |
528
|
|
|
|
|
|
|
|
529
|
|
|
|
|
|
|
# Build an object representing our ground location. |
530
|
|
|
|
|
|
|
|
531
|
3
|
|
|
|
|
11
|
my $sta = $self->station(); |
532
|
|
|
|
|
|
|
|
533
|
3
|
|
|
|
|
1090
|
my @almanac; |
534
|
|
|
|
|
|
|
|
535
|
|
|
|
|
|
|
# Iterate through the background bodies, accumulating data or |
536
|
|
|
|
|
|
|
# complaining about the lack of an almanac() method as |
537
|
|
|
|
|
|
|
# appropriate. |
538
|
|
|
|
|
|
|
|
539
|
|
|
|
|
|
|
my @sky = $self->__choose( $opt->{choose}, $self->{sky} ) |
540
|
3
|
50
|
|
|
|
28
|
or return $self->__wail( 'No bodies selected' ); |
541
|
|
|
|
|
|
|
|
542
|
3
|
|
|
|
|
11
|
foreach my $body ( @sky ) { |
543
|
6
|
50
|
|
|
|
509701
|
$body->can ('almanac') or do { |
544
|
0
|
|
|
|
|
0
|
$self->whinge( |
545
|
|
|
|
|
|
|
ref $body, ' does not support the almanac method'); |
546
|
0
|
|
|
|
|
0
|
next; |
547
|
|
|
|
|
|
|
}; |
548
|
|
|
|
|
|
|
$body->set ( |
549
|
|
|
|
|
|
|
station => $sta, |
550
|
|
|
|
|
|
|
twilight => $self->{_twilight}, |
551
|
6
|
|
|
|
|
50
|
); |
552
|
6
|
|
|
|
|
698
|
push @almanac, $body->almanac_hash( |
553
|
|
|
|
|
|
|
$almanac_start, $almanac_end); |
554
|
|
|
|
|
|
|
} |
555
|
|
|
|
|
|
|
|
556
|
|
|
|
|
|
|
# Record number of events found |
557
|
|
|
|
|
|
|
|
558
|
3
|
|
|
|
|
942187
|
@almanac = grep { $opt->{$_->{almanac}{event}} } @almanac; |
|
27
|
|
|
|
|
86
|
|
559
|
3
|
|
|
|
|
18
|
$self->{events} += @almanac; |
560
|
|
|
|
|
|
|
|
561
|
|
|
|
|
|
|
# Localize the event descriptions if appropriate. |
562
|
|
|
|
|
|
|
|
563
|
3
|
|
|
|
|
17
|
_almanac_localize( @almanac ); |
564
|
|
|
|
|
|
|
|
565
|
|
|
|
|
|
|
# Sort the almanac data by date, and display the results. |
566
|
|
|
|
|
|
|
|
567
|
|
|
|
|
|
|
return $self->__format_data( |
568
|
|
|
|
|
|
|
almanac => [ |
569
|
3
|
|
|
|
|
16
|
sort { $a->{time} <=> $b->{time} } |
|
41
|
|
|
|
|
99
|
|
570
|
|
|
|
|
|
|
@almanac |
571
|
|
|
|
|
|
|
], $opt ); |
572
|
|
|
|
|
|
|
|
573
|
20
|
|
|
20
|
|
10948
|
} |
|
20
|
|
|
|
|
62
|
|
|
20
|
|
|
|
|
112
|
|
574
|
|
|
|
|
|
|
sub _almanac_localize { |
575
|
9
|
|
|
9
|
|
52
|
my @almanac = @_; |
576
|
9
|
|
|
|
|
31
|
foreach my $event ( @almanac ) { |
577
|
|
|
|
|
|
|
$event->{almanac}{description} = __localize( |
578
|
|
|
|
|
|
|
text => [ almanac => $event->{body}->get( 'name' ), |
579
|
|
|
|
|
|
|
$event->{almanac}{event}, $event->{almanac}{detail} ], |
580
|
|
|
|
|
|
|
default => $event->{almanac}{description}, |
581
|
|
|
|
|
|
|
argument => $event->{body}, |
582
|
46
|
|
|
|
|
144
|
); |
583
|
|
|
|
|
|
|
} |
584
|
9
|
|
|
|
|
36
|
return; |
585
|
|
|
|
|
|
|
} |
586
|
|
|
|
|
|
|
|
587
|
|
|
|
|
|
|
sub begin : Verb() Tweak( -unsatisfied ) { |
588
|
5
|
|
|
5
|
1
|
32
|
my ( $self, $opt, @args ) = __arguments( @_ ); |
589
|
|
|
|
|
|
|
$self->_frame_push( |
590
|
5
|
50
|
|
|
|
57
|
begin => @args ? \@args : $self->{frame}[-1]{args}); |
591
|
5
|
|
|
|
|
28
|
$self->{frame}[-1]{level1} = $opt->{level1}; |
592
|
5
|
|
|
|
|
14
|
return; |
593
|
20
|
|
|
20
|
|
7971
|
} |
|
20
|
|
|
|
|
54
|
|
|
20
|
|
|
|
|
102
|
|
594
|
|
|
|
|
|
|
|
595
|
|
|
|
|
|
|
# -level1 is UNSUPPORTED and may be removed without warning. It is only |
596
|
|
|
|
|
|
|
# there for me to screw around with. |
597
|
|
|
|
|
|
|
BEGIN { |
598
|
|
|
|
|
|
|
$ENV{SATPASS2_LEVEL1} |
599
|
20
|
50
|
|
20
|
|
7828
|
and __PACKAGE__->MODIFY_CODE_ATTRIBUTES( |
600
|
|
|
|
|
|
|
\&begin, |
601
|
|
|
|
|
|
|
'Verb( level1! )', |
602
|
|
|
|
|
|
|
); |
603
|
|
|
|
|
|
|
} |
604
|
|
|
|
|
|
|
|
605
|
|
|
|
|
|
|
sub cd : Verb() { |
606
|
2
|
|
|
2
|
1
|
84
|
my ( $self, undef, $dir ) = __arguments( @_ ); # $opt unused |
607
|
2
|
100
|
|
|
|
53
|
if (defined($dir)) { |
608
|
1
|
50
|
|
|
|
46
|
chdir $dir or $self->wail("Can not cd to $dir: $!"); |
609
|
|
|
|
|
|
|
} else { |
610
|
1
|
50
|
|
|
|
32
|
chdir File::HomeDir->my_home() |
611
|
|
|
|
|
|
|
or $self->wail("Can not cd to home: $!"); |
612
|
|
|
|
|
|
|
} |
613
|
2
|
|
|
|
|
78
|
return; |
614
|
20
|
|
|
20
|
|
181
|
} |
|
20
|
|
|
|
|
54
|
|
|
20
|
|
|
|
|
100
|
|
615
|
|
|
|
|
|
|
|
616
|
|
|
|
|
|
|
sub choose : Verb( epoch=s ) { |
617
|
2
|
|
|
2
|
1
|
16
|
my ( $self, $opt, @args ) = __arguments( @_ ); |
618
|
|
|
|
|
|
|
|
619
|
2
|
50
|
|
|
|
14
|
if ($opt->{epoch}) { |
620
|
0
|
|
|
|
|
0
|
my $epoch = $self->__parse_time($opt->{epoch}); |
621
|
|
|
|
|
|
|
$self->{bodies} = [ |
622
|
|
|
|
|
|
|
map { |
623
|
0
|
|
|
|
|
0
|
$_->select($epoch); |
624
|
|
|
|
|
|
|
} |
625
|
|
|
|
|
|
|
$self->_aggregate( $self->{bodies} ) |
626
|
0
|
|
|
|
|
0
|
]; |
627
|
|
|
|
|
|
|
} |
628
|
2
|
50
|
|
|
|
9
|
if ( @args ) { |
629
|
2
|
50
|
|
|
|
5
|
my @bodies = @{ $self->__choose( \@args, $self->{bodies} ) } |
|
2
|
|
|
|
|
12
|
|
630
|
|
|
|
|
|
|
or return $self->__wail( 'No bodies chosen' ); |
631
|
2
|
|
|
|
|
9
|
@{ $self->{bodies} } = @bodies; |
|
2
|
|
|
|
|
16
|
|
632
|
|
|
|
|
|
|
} |
633
|
2
|
|
|
|
|
6
|
return; |
634
|
20
|
|
|
20
|
|
6968
|
} |
|
20
|
|
|
|
|
51
|
|
|
20
|
|
|
|
|
122
|
|
635
|
|
|
|
|
|
|
|
636
|
|
|
|
|
|
|
sub clear : Verb() { |
637
|
5
|
|
|
5
|
1
|
50
|
my ( $self ) = __arguments( @_ ); # $opt, @args unused |
638
|
5
|
|
|
|
|
35
|
@{$self->{bodies}} = (); |
|
5
|
|
|
|
|
91
|
|
639
|
5
|
|
|
|
|
34
|
return; |
640
|
20
|
|
|
20
|
|
5048
|
} |
|
20
|
|
|
|
|
86
|
|
|
20
|
|
|
|
|
120
|
|
641
|
|
|
|
|
|
|
|
642
|
|
|
|
|
|
|
sub dispatch { |
643
|
289
|
|
|
289
|
1
|
829
|
my ($self, $verb, @args) = @_; |
644
|
|
|
|
|
|
|
|
645
|
289
|
50
|
|
|
|
674
|
defined $verb or return; |
646
|
|
|
|
|
|
|
|
647
|
289
|
|
|
|
|
877
|
my $unsatisfied = $self->_in_unsatisfied_if(); |
648
|
|
|
|
|
|
|
|
649
|
289
|
100
|
|
|
|
794
|
if ( $self->{macro}{$verb} ) { |
650
|
19
|
50
|
|
|
|
49
|
$unsatisfied |
651
|
|
|
|
|
|
|
and return; |
652
|
19
|
|
|
|
|
63
|
return $self->_macro( $verb, @args ); |
653
|
|
|
|
|
|
|
} |
654
|
|
|
|
|
|
|
|
655
|
270
|
|
|
|
|
375
|
my $code; |
656
|
270
|
|
|
|
|
557
|
$verb =~ s/ \A core [.] //smx; |
657
|
270
|
100
|
66
|
|
|
1251
|
$code = $self->can($verb) |
658
|
|
|
|
|
|
|
and $self->__get_attr($code, 'Verb') |
659
|
|
|
|
|
|
|
or $self->wail("Unknown interactive method '$verb'"); |
660
|
|
|
|
|
|
|
|
661
|
269
|
|
|
|
|
483
|
my $rslt; |
662
|
|
|
|
|
|
|
$unsatisfied |
663
|
|
|
|
|
|
|
and not $self->__get_attr( $code, Tweak => {} )->{unsatisfied} |
664
|
269
|
100
|
100
|
|
|
1452
|
or $rslt = $code->( $self, @args ); |
665
|
|
|
|
|
|
|
|
666
|
261
|
100
|
|
|
|
39906
|
defined $rslt |
667
|
|
|
|
|
|
|
and $rslt =~ s/ (?
|
668
|
|
|
|
|
|
|
|
669
|
261
|
|
|
|
|
462
|
foreach my $code ( |
670
|
261
|
100
|
|
|
|
1563
|
reverse @{ delete( $self->{frame}[-1]{post_dispatch} ) || [] } |
671
|
|
|
|
|
|
|
) { |
672
|
23
|
|
|
|
|
37
|
my $append; |
673
|
23
|
100
|
|
|
|
55
|
defined( $append = $code->( $self ) ) |
674
|
|
|
|
|
|
|
and $rslt .= $append; |
675
|
|
|
|
|
|
|
} |
676
|
261
|
|
|
|
|
1134
|
return $rslt; |
677
|
|
|
|
|
|
|
} |
678
|
|
|
|
|
|
|
|
679
|
|
|
|
|
|
|
{ |
680
|
|
|
|
|
|
|
my %special = ( |
681
|
|
|
|
|
|
|
begin => sub { |
682
|
|
|
|
|
|
|
my ( $self, $verb ) = @_; |
683
|
|
|
|
|
|
|
$self->_is_interactive() |
684
|
|
|
|
|
|
|
or $self->wail( |
685
|
|
|
|
|
|
|
"'begin' forbidden in non-interactive $verb()" ); |
686
|
|
|
|
|
|
|
return; |
687
|
|
|
|
|
|
|
}, |
688
|
|
|
|
|
|
|
end => sub { |
689
|
|
|
|
|
|
|
my ( $self, $verb ) = @_; |
690
|
|
|
|
|
|
|
$self->wail( "'end' forbidden in $verb()" ); |
691
|
|
|
|
|
|
|
}, |
692
|
|
|
|
|
|
|
); |
693
|
|
|
|
|
|
|
|
694
|
|
|
|
|
|
|
sub _dispatch_check { |
695
|
23
|
|
|
23
|
|
57
|
my ( $self, $verb, $disp ) = @_; |
696
|
23
|
100
|
|
|
|
82
|
my $code = $special{$disp} |
697
|
|
|
|
|
|
|
or return; |
698
|
4
|
|
|
|
|
26
|
return $code->( $self, $verb, $disp ); |
699
|
|
|
|
|
|
|
} |
700
|
|
|
|
|
|
|
} |
701
|
|
|
|
|
|
|
|
702
|
|
|
|
|
|
|
sub drop : Verb() { |
703
|
1
|
|
|
1
|
1
|
6
|
my ( $self, undef, @args ) = __arguments( @_ ); # $opt unused |
704
|
|
|
|
|
|
|
|
705
|
|
|
|
|
|
|
@args |
706
|
1
|
50
|
|
|
|
7
|
or return; |
707
|
|
|
|
|
|
|
|
708
|
|
|
|
|
|
|
my @bodies = @{ |
709
|
1
|
50
|
|
|
|
4
|
$self->__choose( { invert => 1 }, \@args, $self->{bodies} ) } |
|
1
|
|
|
|
|
7
|
|
710
|
|
|
|
|
|
|
or return $self->__wail( 'No bodies left' ); |
711
|
|
|
|
|
|
|
|
712
|
1
|
|
|
|
|
4
|
@{ $self->{bodies} } = @bodies; |
|
1
|
|
|
|
|
3
|
|
713
|
|
|
|
|
|
|
|
714
|
1
|
|
|
|
|
3
|
return; |
715
|
20
|
|
|
20
|
|
14633
|
} |
|
20
|
|
|
|
|
56
|
|
|
20
|
|
|
|
|
113
|
|
716
|
|
|
|
|
|
|
|
717
|
|
|
|
|
|
|
sub dump : method Verb() Tweak( -unsatisfied ) { ## no critic (ProhibitBuiltInHomonyms) |
718
|
0
|
|
|
0
|
1
|
0
|
my ( $self, undef, @arg ) = __arguments( @_ ); # $opt unused |
719
|
|
|
|
|
|
|
|
720
|
0
|
|
|
|
|
0
|
local $self->{time_parser} = ref $self->{time_parser}; |
721
|
|
|
|
|
|
|
|
722
|
0
|
|
|
|
|
0
|
my $dumper = $self->_get_dumper(); |
723
|
|
|
|
|
|
|
|
724
|
|
|
|
|
|
|
@arg |
725
|
0
|
0
|
|
|
|
0
|
or return $dumper->( $self ); |
726
|
|
|
|
|
|
|
|
727
|
0
|
|
|
|
|
0
|
local $_ = shift @arg; |
728
|
|
|
|
|
|
|
|
729
|
|
|
|
|
|
|
ref |
730
|
0
|
0
|
|
|
|
0
|
and return $dumper->( $_ ); |
731
|
|
|
|
|
|
|
|
732
|
|
|
|
|
|
|
m/ \A frames? \z /smxi |
733
|
0
|
0
|
|
|
|
0
|
and return $dumper->( $self->{frame} ); |
734
|
|
|
|
|
|
|
|
735
|
0
|
0
|
|
|
|
0
|
m/ \A tokens? \z /smxi |
736
|
|
|
|
|
|
|
and return $dumper->( $self->__tokenize( @arg ) ); |
737
|
|
|
|
|
|
|
|
738
|
|
|
|
|
|
|
m/ \A twilight \z /smxi |
739
|
|
|
|
|
|
|
and return $dumper->( |
740
|
0
|
0
|
|
|
|
0
|
{ map { $_ => $self->{$_} } qw{ twilight _twilight } } ); |
|
0
|
|
|
|
|
0
|
|
741
|
|
|
|
|
|
|
|
742
|
0
|
|
|
|
|
0
|
my @stuff = $self->__choose( [ $_ ], $self->{bodies} ); |
743
|
0
|
0
|
|
|
|
0
|
if ( defined( my $inx = $self->_find_in_sky( $_ ) ) ) { |
744
|
0
|
|
|
|
|
0
|
push @stuff, $self->{sky}[$inx]; |
745
|
|
|
|
|
|
|
} |
746
|
|
|
|
|
|
|
@stuff |
747
|
0
|
0
|
|
|
|
0
|
and return $dumper->( @stuff ); |
748
|
|
|
|
|
|
|
|
749
|
0
|
|
|
|
|
0
|
$self->whinge( "Dump argument '$_' not recognized" ); |
750
|
|
|
|
|
|
|
|
751
|
0
|
|
|
|
|
0
|
return; |
752
|
20
|
|
|
20
|
|
9755
|
} |
|
20
|
|
|
|
|
50
|
|
|
20
|
|
|
|
|
98
|
|
753
|
|
|
|
|
|
|
|
754
|
|
|
|
|
|
|
sub echo : Verb( n! ) { |
755
|
44
|
|
|
44
|
1
|
183
|
my ( undef, $opt, @args ) = __arguments( @_ ); # Invocant unused |
756
|
44
|
|
|
|
|
175
|
my $output = join( ' ', @args ); |
757
|
44
|
50
|
|
|
|
152
|
$opt->{n} or $output .= "\n"; |
758
|
44
|
|
|
|
|
137
|
return $output; |
759
|
20
|
|
|
20
|
|
5975
|
} |
|
20
|
|
|
|
|
52
|
|
|
20
|
|
|
|
|
87
|
|
760
|
|
|
|
|
|
|
|
761
|
|
|
|
|
|
|
sub else : method Verb() Tweak( -unsatisfied ) { ## no critic (ProhibitBuiltInHomonyms) |
762
|
2
|
|
|
2
|
1
|
16
|
my ( $self ) = __arguments( @_ ); # $opt, @args unused |
763
|
|
|
|
|
|
|
|
764
|
2
|
|
|
|
|
27
|
@{ $self->{frame} } > 1 |
765
|
|
|
|
|
|
|
and 'begin' eq $self->{frame}[-1]{type} |
766
|
|
|
|
|
|
|
and 'if' eq $self->{frame}[-2]{type} |
767
|
2
|
50
|
33
|
|
|
12
|
or $self->wail( 'Else without if ... then begin' ); |
|
|
|
33
|
|
|
|
|
768
|
|
|
|
|
|
|
|
769
|
2
|
50
|
|
|
|
15
|
$self->{frame}[-1]{in_else}++ |
770
|
|
|
|
|
|
|
and $self->wail( 'Only one else may follow an if' ); |
771
|
|
|
|
|
|
|
|
772
|
2
|
|
|
|
|
16
|
return $self->_twiddle_condition( ! $self->{frame}[-2]{condition} ); |
773
|
20
|
|
|
20
|
|
6465
|
} |
|
20
|
|
|
|
|
54
|
|
|
20
|
|
|
|
|
124
|
|
774
|
|
|
|
|
|
|
|
775
|
|
|
|
|
|
|
sub _twiddle_condition { |
776
|
4
|
|
|
4
|
|
18
|
my ( $self, $cond ) = @_; |
777
|
|
|
|
|
|
|
|
778
|
|
|
|
|
|
|
# Here is where I pay for the convenience of the if() |
779
|
|
|
|
|
|
|
# implementation. The if() itself is a frame because I do not yet |
780
|
|
|
|
|
|
|
# know if it will entail a begin(). But I can't do an else() unless |
781
|
|
|
|
|
|
|
# there is in fact a begin(), which creates another frame. So I end |
782
|
|
|
|
|
|
|
# up twiddling values in both frames. |
783
|
|
|
|
|
|
|
|
784
|
|
|
|
|
|
|
$self->{frame}[-1]{unsatisfied_if} = |
785
|
|
|
|
|
|
|
$self->{frame}[-2]{unsatisfied_if} = |
786
|
|
|
|
|
|
|
! $cond || ( |
787
|
|
|
|
|
|
|
@{ $self->{frame} } > 2 ? |
788
|
|
|
|
|
|
|
$self->{frame}[-3]{unsatisfied_if} : |
789
|
4
|
|
66
|
|
|
16
|
0 |
790
|
|
|
|
|
|
|
); |
791
|
|
|
|
|
|
|
|
792
|
|
|
|
|
|
|
$self->{frame}[-1]{condition} = |
793
|
4
|
|
|
|
|
9
|
$self->{frame}[-2]{condition} = $cond; |
794
|
|
|
|
|
|
|
|
795
|
4
|
|
|
|
|
18
|
return; |
796
|
|
|
|
|
|
|
} |
797
|
|
|
|
|
|
|
|
798
|
|
|
|
|
|
|
sub end : Verb() Tweak( -unsatisfied ) { |
799
|
5
|
|
|
5
|
1
|
41
|
my ( $self ) = __arguments( @_ ); # $opt, @args unused |
800
|
|
|
|
|
|
|
|
801
|
5
|
50
|
|
|
|
45
|
$self->{frame}[-1]{type} eq 'begin' |
802
|
|
|
|
|
|
|
or $self->wail( 'End without begin' ); |
803
|
5
|
|
|
|
|
46
|
$self->_frame_pop(); |
804
|
5
|
|
|
|
|
18
|
return; |
805
|
20
|
|
|
20
|
|
8369
|
} |
|
20
|
|
|
|
|
56
|
|
|
20
|
|
|
|
|
122
|
|
806
|
|
|
|
|
|
|
|
807
|
|
|
|
|
|
|
sub error : Verb() { |
808
|
1
|
|
|
1
|
1
|
8
|
my ( $self, undef, @arg ) = __arguments( @_ ); |
809
|
|
|
|
|
|
|
@arg |
810
|
1
|
50
|
|
|
|
10
|
or push @arg, 'An error has occurred'; |
811
|
1
|
|
|
|
|
11
|
$self->wail( @arg ); |
812
|
0
|
|
|
|
|
0
|
return; |
813
|
20
|
|
|
20
|
|
5777
|
} |
|
20
|
|
|
|
|
74
|
|
|
20
|
|
|
|
|
104
|
|
814
|
|
|
|
|
|
|
|
815
|
|
|
|
|
|
|
# Tokenize and execute one or more commands. Optionally (and |
816
|
|
|
|
|
|
|
# unsupportedly) you can pass a code reference as the first argument. |
817
|
|
|
|
|
|
|
# This code reference will be used to fetch commands when the arguments |
818
|
|
|
|
|
|
|
# are exhausted. IF you pass your own code reference, we return after |
819
|
|
|
|
|
|
|
# the first command, since the code reference is presumed to manage the |
820
|
|
|
|
|
|
|
# input stream itself. |
821
|
|
|
|
|
|
|
sub execute { |
822
|
264
|
|
|
264
|
1
|
765
|
my ($self, @args) = @_; |
823
|
264
|
|
|
|
|
663
|
my $accum; |
824
|
|
|
|
|
|
|
my $in; |
825
|
264
|
|
|
|
|
0
|
my $extern; |
826
|
264
|
100
|
|
|
|
730
|
if ( CODE_REF eq ref $args[0] ) { |
827
|
13
|
|
|
|
|
26
|
$extern = shift @args; |
828
|
|
|
|
|
|
|
$in = sub { |
829
|
21
|
|
|
21
|
|
62
|
my ( $prompt ) = @_; |
830
|
21
|
100
|
|
|
|
87
|
@args and return shift @args; |
831
|
8
|
|
|
|
|
51
|
return $extern->( $prompt ); |
832
|
13
|
|
|
|
|
70
|
}; |
833
|
|
|
|
|
|
|
} else { |
834
|
251
|
|
|
502
|
|
1266
|
$in = sub { return shift @args }; |
|
502
|
|
|
|
|
1616
|
|
835
|
|
|
|
|
|
|
} |
836
|
264
|
|
|
|
|
633
|
@args = map { split qr{ (?<= \n ) }smx, $_ } @args; |
|
265
|
|
|
|
|
3243
|
|
837
|
264
|
|
|
|
|
930
|
while ( defined ( local $_ = $in->( $self->get( 'prompt' ) ) ) ) { |
838
|
280
|
50
|
|
|
|
791
|
$self->{echo} and $self->whinge($self->get( 'prompt' ), $_); |
839
|
280
|
100
|
|
|
|
859
|
m/ \A \s* [#] /smx and next; |
840
|
277
|
|
|
|
|
644
|
my $stdout = $self->{frame}[-1]{stdout}; |
841
|
|
|
|
|
|
|
my ($args, $redirect) = $self->__tokenize( |
842
|
277
|
|
|
|
|
1211
|
{ in => $in }, $_, $self->{frame}[-1]{args}); |
843
|
|
|
|
|
|
|
# NOTICE |
844
|
|
|
|
|
|
|
# |
845
|
|
|
|
|
|
|
# The execute_filter attribute is undocumented and unsupported. |
846
|
|
|
|
|
|
|
# It exists only so I can scavenge the user's initialization |
847
|
|
|
|
|
|
|
# file for the (possible) Space Track username and password, to |
848
|
|
|
|
|
|
|
# be used in testing, without being subject to any other |
849
|
|
|
|
|
|
|
# undesired side effects, such as running a prediction and |
850
|
|
|
|
|
|
|
# exiting. If I change my mind on how or whether to do this, |
851
|
|
|
|
|
|
|
# execute_filter will be altered or retracted without warning, |
852
|
|
|
|
|
|
|
# much less a deprecation cycle. If you have a legitimate need |
853
|
|
|
|
|
|
|
# for this functionality, contact me. |
854
|
|
|
|
|
|
|
# |
855
|
|
|
|
|
|
|
# YOU HAVE BEEN WARNED. |
856
|
273
|
100
|
|
|
|
1117
|
$self->{execute_filter}->( $self, $args ) or next; |
857
|
267
|
100
|
|
|
|
1154
|
@{ $args } or next; |
|
267
|
|
|
|
|
638
|
|
858
|
266
|
100
|
|
|
|
610
|
if ($redirect->{'>'}) { |
859
|
1
|
|
|
|
|
16
|
my ( $mode, $name ) = map { $redirect->{'>'}{$_} } qw{ mode name }; |
|
2
|
|
|
|
|
6
|
|
860
|
1
|
|
|
|
|
2
|
my $fh; |
861
|
|
|
|
|
|
|
$stdout = sub { |
862
|
1
|
|
|
1
|
|
3
|
my ( $output ) = @_; |
863
|
1
|
|
33
|
|
|
23
|
$fh ||= $self->_file_opener( $name, $mode ); |
864
|
1
|
|
|
|
|
15
|
$fh->print( $output ); |
865
|
1
|
|
|
|
|
12
|
return; |
866
|
1
|
|
|
|
|
7
|
}; |
867
|
|
|
|
|
|
|
} |
868
|
|
|
|
|
|
|
|
869
|
|
|
|
|
|
|
# {localout} is the output to be used for this command. It goes |
870
|
|
|
|
|
|
|
# in the frame stack because our command may start a new frame, |
871
|
|
|
|
|
|
|
# and _frame_push() needs to have a place to get the correct |
872
|
|
|
|
|
|
|
# output handle. |
873
|
|
|
|
|
|
|
|
874
|
266
|
|
|
|
|
450
|
my $frame_depth = $#{$self->{frame}}; |
|
266
|
|
|
|
|
605
|
|
875
|
266
|
|
|
|
|
700
|
$self->{frame}[-1]{localout} = $stdout; |
876
|
|
|
|
|
|
|
|
877
|
266
|
|
|
|
|
769
|
my $output = $self->dispatch( @$args ); |
878
|
|
|
|
|
|
|
|
879
|
256
|
|
|
|
|
967
|
$#{$self->{frame}} >= $frame_depth |
880
|
256
|
100
|
|
|
|
426
|
and delete $self->{frame}[ $frame_depth ]{localout}; |
881
|
|
|
|
|
|
|
|
882
|
256
|
100
|
|
|
|
1172
|
$self->_execute_output( $output, |
883
|
|
|
|
|
|
|
defined $stdout ? $stdout : \$accum ); |
884
|
|
|
|
|
|
|
|
885
|
256
|
100
|
|
|
|
1558
|
$extern and last; |
886
|
|
|
|
|
|
|
} |
887
|
250
|
|
|
|
|
1862
|
return $accum; |
888
|
|
|
|
|
|
|
} |
889
|
|
|
|
|
|
|
|
890
|
|
|
|
|
|
|
# $satpass2->_execute(...); |
891
|
|
|
|
|
|
|
# |
892
|
|
|
|
|
|
|
# This subroutine calls $satpass2->execute() once for each |
893
|
|
|
|
|
|
|
# argument. The call is wrapped in an eval{}; if an exception |
894
|
|
|
|
|
|
|
# occurs the user is notified via warn. |
895
|
|
|
|
|
|
|
|
896
|
|
|
|
|
|
|
sub _execute { |
897
|
0
|
|
|
0
|
|
0
|
my ($self, @args) = @_; |
898
|
|
|
|
|
|
|
my $in = CODE_REF eq ref $args[0] ? shift @args : sub { return shift |
899
|
0
|
0
|
|
0
|
|
0
|
@args }; |
|
0
|
|
|
|
|
0
|
|
900
|
0
|
|
|
|
|
0
|
while ( @args ) { |
901
|
0
|
|
|
0
|
|
0
|
local $SIG{INT} = sub {die "\n$interrupted\n"}; |
|
0
|
|
|
|
|
0
|
|
902
|
0
|
0
|
|
|
|
0
|
eval { |
903
|
0
|
|
|
|
|
0
|
$self->execute( $in, shift @args ); |
904
|
0
|
|
|
|
|
0
|
1; |
905
|
|
|
|
|
|
|
} or warn $@; # Not whinge, since presumably we already did. |
906
|
|
|
|
|
|
|
} |
907
|
0
|
|
|
|
|
0
|
return; |
908
|
|
|
|
|
|
|
} |
909
|
|
|
|
|
|
|
|
910
|
|
|
|
|
|
|
# $satpass2->_execute_output( $output, $stdout ); |
911
|
|
|
|
|
|
|
# |
912
|
|
|
|
|
|
|
# If $output is defined, sends it to $stdout. |
913
|
|
|
|
|
|
|
|
914
|
|
|
|
|
|
|
sub _execute_output { |
915
|
256
|
|
|
256
|
|
663
|
my ( undef, $output, $stdout ) = @_; # Invocant unused |
916
|
256
|
100
|
|
|
|
728
|
defined $output or return; |
917
|
152
|
|
|
|
|
403
|
my $ref = ref $stdout; |
918
|
152
|
50
|
|
|
|
516
|
if ( !defined $stdout ) { |
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
919
|
0
|
|
|
|
|
0
|
return $output; |
920
|
|
|
|
|
|
|
} elsif ( SCALAR_REF eq $ref ) { |
921
|
149
|
|
|
|
|
421
|
$$stdout .= $output; |
922
|
|
|
|
|
|
|
} elsif ( CODE_REF eq $ref ) { |
923
|
2
|
|
|
|
|
6
|
$stdout->( $output ); |
924
|
|
|
|
|
|
|
} elsif ( ARRAY_REF eq $ref ) { |
925
|
1
|
|
|
|
|
11
|
push @$stdout, split qr{ (?<=\n) }smx, $output; |
926
|
|
|
|
|
|
|
} else { |
927
|
0
|
|
|
|
|
0
|
$stdout->print( $output ); |
928
|
|
|
|
|
|
|
} |
929
|
152
|
|
|
|
|
341
|
return; |
930
|
|
|
|
|
|
|
} |
931
|
|
|
|
|
|
|
|
932
|
|
|
|
|
|
|
sub exit : method Verb() { ## no critic (ProhibitBuiltInHomonyms) |
933
|
1
|
|
|
1
|
1
|
5
|
my ( $self ) = __arguments( @_ ); # $opt, @args unused |
934
|
|
|
|
|
|
|
|
935
|
1
|
|
|
|
|
7
|
$self->_frame_pop(1); # Leave only the inital frame. |
936
|
|
|
|
|
|
|
|
937
|
1
|
|
|
|
|
2
|
eval { ## no critic (RequireCheckingReturnValueOfEval) |
938
|
20
|
|
|
20
|
|
22220
|
no warnings qw{exiting}; |
|
20
|
|
|
|
|
58
|
|
|
20
|
|
|
|
|
1888
|
|
939
|
1
|
|
|
|
|
9
|
last SATPASS2_EXECUTE; |
940
|
|
|
|
|
|
|
}; |
941
|
0
|
|
|
|
|
0
|
$self->whinge("$@Exiting Perl"); |
942
|
0
|
|
|
|
|
0
|
exit; |
943
|
|
|
|
|
|
|
|
944
|
20
|
|
|
20
|
|
153
|
} |
|
20
|
|
|
|
|
72
|
|
|
20
|
|
|
|
|
118
|
|
945
|
|
|
|
|
|
|
|
946
|
|
|
|
|
|
|
sub export : Verb() { |
947
|
4
|
|
|
4
|
1
|
33
|
my ( $self, undef, $name, @args ) = __arguments( @_ ); # $opt unused |
948
|
4
|
100
|
|
|
|
38
|
if ($mutator{$name}) { |
949
|
1
|
50
|
|
|
|
8
|
@args and $self->set ($name, shift @args); |
950
|
1
|
|
|
|
|
5
|
$self->{exported}{$name} = 1; |
951
|
|
|
|
|
|
|
} else { |
952
|
3
|
100
|
|
|
|
47
|
@args or return $self->wail( 'You must specify a value' ); |
953
|
2
|
|
|
|
|
32
|
$self->{exported}{$name} = shift @args; |
954
|
|
|
|
|
|
|
} |
955
|
3
|
|
|
|
|
11
|
return; |
956
|
20
|
|
|
20
|
|
6036
|
} |
|
20
|
|
|
|
|
59
|
|
|
20
|
|
|
|
|
113
|
|
957
|
|
|
|
|
|
|
|
958
|
|
|
|
|
|
|
# Attributes must all be on one line to process correctly under Perl |
959
|
|
|
|
|
|
|
# 5.8.8. |
960
|
|
|
|
|
|
|
sub flare : Verb( algorithm=s am! choose=s@ day! dump! pm! questionable|spare! quiet! tz|zone=s ) |
961
|
|
|
|
|
|
|
{ |
962
|
0
|
|
|
0
|
1
|
0
|
my ( $self, $opt, @args ) = __arguments( @_ ); |
963
|
0
|
|
|
|
|
0
|
HAVE_TLE_IRIDIUM |
964
|
|
|
|
|
|
|
or $self->wail( 'Astro::Coord::ECI::TLE::Iridium not available' ); |
965
|
0
|
|
|
|
|
0
|
my $pass_start = $self->__parse_time ( |
966
|
|
|
|
|
|
|
shift @args, $self->_get_day_noon()); |
967
|
0
|
|
0
|
|
|
0
|
my $pass_end = $self->__parse_time (shift @args || '+7'); |
968
|
0
|
0
|
|
|
|
0
|
$pass_start >= $pass_end |
969
|
|
|
|
|
|
|
and $self->wail( 'End time must be after start time' ); |
970
|
0
|
|
|
|
|
0
|
my $sta = $self->station(); |
971
|
|
|
|
|
|
|
|
972
|
0
|
|
|
|
|
0
|
my $max_mirror_angle = deg2rad( $self->{max_mirror_angle} ); |
973
|
0
|
|
|
|
|
0
|
my $horizon = deg2rad ($self->{horizon}); |
974
|
0
|
|
|
|
|
0
|
my $twilight = $self->{_twilight}; |
975
|
0
|
|
|
|
|
0
|
my @flare_mag = ($self->{flare_mag_night}, $self->{flare_mag_day}); |
976
|
|
|
|
|
|
|
my $zone = exists $opt->{tz} ? $opt->{tz} : |
977
|
|
|
|
|
|
|
$self->{formatter}->gmt() ? 0 : |
978
|
0
|
0
|
0
|
|
|
0
|
$self->{formatter}->tz() || undef; |
|
|
0
|
|
|
|
|
|
979
|
|
|
|
|
|
|
|
980
|
0
|
|
|
|
|
0
|
$self->_apply_boolean_default( |
981
|
|
|
|
|
|
|
$opt, 0, qw{ am day pm } ); |
982
|
|
|
|
|
|
|
|
983
|
|
|
|
|
|
|
# Decide which model to use. |
984
|
|
|
|
|
|
|
|
985
|
0
|
|
|
|
|
0
|
my $model = $self->{model}; |
986
|
|
|
|
|
|
|
|
987
|
|
|
|
|
|
|
# Select only the bodies capable of flaring. |
988
|
|
|
|
|
|
|
|
989
|
0
|
|
|
|
|
0
|
my @active; |
990
|
0
|
|
|
|
|
0
|
foreach my $tle ( $self->_aggregate( |
991
|
|
|
|
|
|
|
scalar $self->__choose( $opt->{choose}, $self->{bodies} ) |
992
|
|
|
|
|
|
|
) ) |
993
|
|
|
|
|
|
|
{ |
994
|
0
|
0
|
|
|
|
0
|
$tle->can_flare( $opt->{questionable} ) or next; |
995
|
|
|
|
|
|
|
$tle->set ( |
996
|
|
|
|
|
|
|
algorithm => $opt->{algorithm} || 'fixed', |
997
|
|
|
|
|
|
|
backdate => $self->{backdate}, |
998
|
|
|
|
|
|
|
edge_of_earths_shadow => $self->{edge_of_earths_shadow}, |
999
|
|
|
|
|
|
|
horizon => $horizon, |
1000
|
|
|
|
|
|
|
twilight => $twilight, |
1001
|
|
|
|
|
|
|
model => $model, |
1002
|
|
|
|
|
|
|
am => $opt->{am}, |
1003
|
|
|
|
|
|
|
max_mirror_angle => $max_mirror_angle, |
1004
|
|
|
|
|
|
|
day => $opt->{day}, |
1005
|
|
|
|
|
|
|
pm => $opt->{pm}, |
1006
|
|
|
|
|
|
|
extinction => $self->{extinction}, |
1007
|
0
|
|
0
|
|
|
0
|
station => $sta, |
1008
|
|
|
|
|
|
|
zone => $zone, |
1009
|
|
|
|
|
|
|
); |
1010
|
0
|
|
|
|
|
0
|
push @active, $tle; |
1011
|
|
|
|
|
|
|
} |
1012
|
0
|
0
|
|
|
|
0
|
@active or return $self->__wail( 'No bodies capable of flaring' ); |
1013
|
|
|
|
|
|
|
|
1014
|
0
|
|
|
|
|
0
|
my @flares; |
1015
|
0
|
|
|
|
|
0
|
foreach my $tle (@active) { |
1016
|
|
|
|
|
|
|
eval { |
1017
|
0
|
|
|
|
|
0
|
push @flares, $tle->flare( $pass_start, $pass_end ); |
1018
|
0
|
|
|
|
|
0
|
1; |
1019
|
0
|
0
|
|
|
|
0
|
} or do { |
1020
|
0
|
0
|
|
|
|
0
|
$@ =~ m/ \Q$interrupted\E /smxo and $self->wail($@); |
1021
|
0
|
0
|
|
|
|
0
|
$opt->{quiet} or $self->whinge($@); |
1022
|
|
|
|
|
|
|
}; |
1023
|
|
|
|
|
|
|
} |
1024
|
|
|
|
|
|
|
|
1025
|
|
|
|
|
|
|
# Record number of events found |
1026
|
|
|
|
|
|
|
|
1027
|
0
|
|
|
|
|
0
|
@flares = sort { $a->{time} <=> $b->{time} } |
1028
|
0
|
|
|
|
|
0
|
grep { $_->{magnitude} <= $flare_mag[ |
1029
|
0
|
0
|
|
|
|
0
|
( $_->{type} eq 'day' ? 1 : 0 ) ] } |
1030
|
|
|
|
|
|
|
@flares; |
1031
|
0
|
|
|
|
|
0
|
$self->{events} += @flares; |
1032
|
|
|
|
|
|
|
|
1033
|
0
|
|
|
|
|
0
|
return $self->__format_data( flare => \@flares, $opt ); |
1034
|
20
|
|
|
20
|
|
13392
|
} |
|
20
|
|
|
|
|
55
|
|
|
20
|
|
|
|
|
109
|
|
1035
|
|
|
|
|
|
|
|
1036
|
|
|
|
|
|
|
sub formatter : Verb() Tweak( -completion _readline_complete_subcommand ) { |
1037
|
9
|
50
|
|
9
|
1
|
49
|
splice @_, ( HASH_REF eq ref $_[1] ? 2 : 1 ), 0, 'formatter'; |
1038
|
9
|
|
|
|
|
43
|
goto &_helper_handler; |
1039
|
20
|
|
|
20
|
|
4993
|
} |
|
20
|
|
|
|
|
56
|
|
|
20
|
|
|
|
|
113
|
|
1040
|
|
|
|
|
|
|
|
1041
|
|
|
|
|
|
|
# Calls to the following _formatter_sub method are generated dynamically |
1042
|
|
|
|
|
|
|
# above, so there is no way Perl::Critic can find them. |
1043
|
|
|
|
|
|
|
|
1044
|
|
|
|
|
|
|
sub _formatter_sub { ## no critic (ProhibitUnusedPrivateSubroutines) |
1045
|
0
|
|
|
0
|
|
0
|
my ( $app, $text, $line, $start, @arg ) = @_; |
1046
|
0
|
|
|
|
|
0
|
my $fmtr = $app->get( 'formatter' ); |
1047
|
0
|
0
|
|
|
|
0
|
if ( @arg == 2 ) { |
1048
|
0
|
|
|
|
|
0
|
my @list = qw{ |
1049
|
|
|
|
|
|
|
date_format |
1050
|
|
|
|
|
|
|
desired_equinox_dynamical |
1051
|
|
|
|
|
|
|
gmt |
1052
|
|
|
|
|
|
|
local_coord |
1053
|
|
|
|
|
|
|
time_format |
1054
|
|
|
|
|
|
|
tz |
1055
|
|
|
|
|
|
|
}; |
1056
|
0
|
0
|
|
|
|
0
|
$fmtr->can( '__list_templates' ) |
1057
|
|
|
|
|
|
|
and push @list, 'template'; |
1058
|
0
|
|
|
|
|
0
|
my $re = qr/ \A \Q$arg[1]\E /smx; |
1059
|
0
|
|
|
|
|
0
|
return [ grep { $_ =~ $re } sort @list ]; |
|
0
|
|
|
|
|
0
|
|
1060
|
|
|
|
|
|
|
} |
1061
|
0
|
0
|
|
|
|
0
|
my $code = $app->can( "_formatter_complete_$arg[1]" ) |
1062
|
|
|
|
|
|
|
or return; |
1063
|
|
|
|
|
|
|
|
1064
|
0
|
|
|
|
|
0
|
my $r; |
1065
|
0
|
0
|
|
|
|
0
|
$r = $app->_readline_complete_options( $code, $text, $line, |
1066
|
|
|
|
|
|
|
$start ) |
1067
|
|
|
|
|
|
|
and return $r; |
1068
|
|
|
|
|
|
|
|
1069
|
0
|
|
|
|
|
0
|
return $code->( $app, @arg ); |
1070
|
|
|
|
|
|
|
} |
1071
|
|
|
|
|
|
|
|
1072
|
|
|
|
|
|
|
# Calls to the following _formatter_complete_... methods are generated |
1073
|
|
|
|
|
|
|
# dynamically above, so there is no way Perl::Critic can find them. |
1074
|
|
|
|
|
|
|
# The Verb attribute must aggree with _helper_handler(). |
1075
|
|
|
|
|
|
|
|
1076
|
|
|
|
|
|
|
sub _formatter_complete_template : Verb( changes! raw! ) { ## no critic (ProhibitUnusedPrivateSubroutines) |
1077
|
0
|
|
|
0
|
|
0
|
my ( $app, undef, @arg ) = __arguments( @_ ); |
1078
|
0
|
|
|
|
|
0
|
my $fmtr = $app->get( 'formatter' ); |
1079
|
0
|
|
|
|
|
0
|
my $re = qr/ \A \Q$arg[2]\E /smx; |
1080
|
|
|
|
|
|
|
return [ |
1081
|
0
|
|
|
|
|
0
|
grep { $_ =~ $re } |
|
0
|
|
|
|
|
0
|
|
1082
|
|
|
|
|
|
|
sort( $fmtr->__list_templates() ) |
1083
|
|
|
|
|
|
|
]; |
1084
|
20
|
|
|
20
|
|
10663
|
} |
|
20
|
|
|
|
|
76
|
|
|
20
|
|
|
|
|
104
|
|
1085
|
|
|
|
|
|
|
|
1086
|
|
|
|
|
|
|
sub geocode : Verb( debug! ) { |
1087
|
0
|
|
|
0
|
1
|
0
|
my ( $self, $opt, $loc ) = __arguments( @_ ); |
1088
|
|
|
|
|
|
|
|
1089
|
0
|
|
|
|
|
0
|
my $set_loc; |
1090
|
0
|
0
|
|
|
|
0
|
if ( defined $loc ) { |
1091
|
0
|
|
|
|
|
0
|
$set_loc = 1; |
1092
|
|
|
|
|
|
|
} else { |
1093
|
0
|
|
|
|
|
0
|
$loc = $self->get( 'location' ); |
1094
|
|
|
|
|
|
|
} |
1095
|
|
|
|
|
|
|
|
1096
|
0
|
|
|
|
|
0
|
my $geocoder = $self->_helper_get_object( 'geocoder' ); |
1097
|
|
|
|
|
|
|
|
1098
|
0
|
|
|
|
|
0
|
my @rslt = $geocoder->geocode( $loc ); |
1099
|
|
|
|
|
|
|
|
1100
|
0
|
|
|
|
|
0
|
my $output; |
1101
|
0
|
0
|
|
|
|
0
|
if ( @rslt == 1 ) { |
1102
|
|
|
|
|
|
|
$set_loc |
1103
|
0
|
0
|
|
|
|
0
|
and $self->set( location => $rslt[0]{description} ); |
1104
|
0
|
|
|
|
|
0
|
$self->set( map { $_ => $rslt[0]{$_} } qw{ latitude |
|
0
|
|
|
|
|
0
|
|
1105
|
|
|
|
|
|
|
longitude } ); |
1106
|
0
|
0
|
|
|
|
0
|
$output .= $self->show( |
1107
|
|
|
|
|
|
|
( $set_loc ? 'location' : () ), qw{latitude longitude} ); |
1108
|
0
|
0
|
|
|
|
0
|
if ( $self->get( 'autoheight' ) ) { |
1109
|
0
|
|
|
|
|
0
|
$opt->{geocoding} = 1; |
1110
|
0
|
|
|
|
|
0
|
$output .= $self->_height_us($opt); |
1111
|
|
|
|
|
|
|
} |
1112
|
|
|
|
|
|
|
} else { |
1113
|
0
|
|
|
|
|
0
|
foreach my $poi ( @rslt ) { |
1114
|
0
|
|
|
|
|
0
|
$output .= join ' ', map { $poi->{$_} } qw{ latitude |
|
0
|
|
|
|
|
0
|
|
1115
|
|
|
|
|
|
|
longitude description }; |
1116
|
0
|
|
|
|
|
0
|
$output =~ s/ (?: \A | (?
|
1117
|
|
|
|
|
|
|
} |
1118
|
|
|
|
|
|
|
} |
1119
|
0
|
|
|
|
|
0
|
return $output; |
1120
|
20
|
|
|
20
|
|
9255
|
} |
|
20
|
|
|
|
|
52
|
|
|
20
|
|
|
|
|
131
|
|
1121
|
|
|
|
|
|
|
|
1122
|
|
|
|
|
|
|
sub geodetic : Verb() { |
1123
|
0
|
|
|
0
|
1
|
0
|
my ( $self, undef, $name, $lat, $lon, $alt ) = __arguments( @_ ); # $opt unused |
1124
|
0
|
0
|
|
|
|
0
|
@_ == 5 or $self->wail( 'Want exactly four arguments' ); |
1125
|
0
|
|
|
|
|
0
|
my $body = Astro::Coord::ECI::TLE->new( |
1126
|
|
|
|
|
|
|
name => $name, |
1127
|
|
|
|
|
|
|
id => '', |
1128
|
|
|
|
|
|
|
model => 'null', |
1129
|
|
|
|
|
|
|
)->geodetic( |
1130
|
|
|
|
|
|
|
deg2rad( $self->__parse_angle( $lat ) ), |
1131
|
|
|
|
|
|
|
deg2rad( $self->__parse_angle( $lon ) ), |
1132
|
|
|
|
|
|
|
$self->__parse_distance( $alt ), |
1133
|
|
|
|
|
|
|
); |
1134
|
0
|
|
|
|
|
0
|
push @{ $self->{bodies} }, $body; |
|
0
|
|
|
|
|
0
|
|
1135
|
0
|
|
|
|
|
0
|
return; |
1136
|
20
|
|
|
20
|
|
6234
|
} |
|
20
|
|
|
|
|
76
|
|
|
20
|
|
|
|
|
131
|
|
1137
|
|
|
|
|
|
|
|
1138
|
|
|
|
|
|
|
sub get { |
1139
|
927
|
|
|
927
|
1
|
2292
|
my ($self, $name) = @_; |
1140
|
927
|
|
|
|
|
2982
|
$self->_attribute_exists( $name ); |
1141
|
927
|
|
|
|
|
2947
|
$self->_deprecation_notice( attribute => $name ); |
1142
|
927
|
|
|
|
|
3280
|
return $accessor{$name}->($self, $name); |
1143
|
|
|
|
|
|
|
} |
1144
|
|
|
|
|
|
|
|
1145
|
|
|
|
|
|
|
sub height : Verb( debug! ) { |
1146
|
0
|
|
|
0
|
1
|
0
|
return _height_us( __arguments( @_ ) ); |
1147
|
20
|
|
|
20
|
|
6130
|
} |
|
20
|
|
|
|
|
72
|
|
|
20
|
|
|
|
|
116
|
|
1148
|
|
|
|
|
|
|
|
1149
|
|
|
|
|
|
|
sub _height_us { |
1150
|
0
|
|
|
0
|
|
0
|
my ($self, $opt, @args) = @_; |
1151
|
0
|
|
|
|
|
0
|
$self->_load_module ('Geo::WebService::Elevation::USGS'); |
1152
|
0
|
|
|
|
|
0
|
my $eq = Geo::WebService::Elevation::USGS->new( |
1153
|
|
|
|
|
|
|
places => 2, # Service returns unreasonable precision |
1154
|
|
|
|
|
|
|
units => 'METERS', # default for service is 'FEET' |
1155
|
|
|
|
|
|
|
croak => 0, # Handle our own errors |
1156
|
|
|
|
|
|
|
); |
1157
|
0
|
0
|
|
|
|
0
|
@args or push @args, $self->get('latitude'), $self->get('longitude'); |
1158
|
0
|
|
|
|
|
0
|
my $output; |
1159
|
0
|
|
|
|
|
0
|
my ( $rslt ) = $eq->elevation(@args); |
1160
|
0
|
0
|
|
|
|
0
|
if ( $eq->is_valid( $rslt ) ) { |
1161
|
0
|
|
|
|
|
0
|
$self->set( height => $rslt->{Elevation} ); |
1162
|
|
|
|
|
|
|
} else { |
1163
|
|
|
|
|
|
|
$opt->{geocoding} |
1164
|
0
|
0
|
0
|
|
|
0
|
or $self->wail( $eq->error() || 'No valid result found' ); |
1165
|
0
|
|
|
|
|
0
|
$self->set( height => 0 ); |
1166
|
0
|
|
|
|
|
0
|
$output .= "# Unable to obtain height. Setting to 0\n"; |
1167
|
|
|
|
|
|
|
} |
1168
|
0
|
|
|
|
|
0
|
$output .= $self->show( 'height' ); |
1169
|
0
|
|
|
|
|
0
|
return $output; |
1170
|
|
|
|
|
|
|
} |
1171
|
|
|
|
|
|
|
|
1172
|
|
|
|
|
|
|
sub help : Verb() { |
1173
|
0
|
|
|
0
|
1
|
0
|
my ( $self, undef, $arg ) = __arguments( @_ ); # $opt unused |
1174
|
0
|
0
|
|
|
|
0
|
defined $arg |
1175
|
|
|
|
|
|
|
or $arg = ''; |
1176
|
|
|
|
|
|
|
defined $self->{_help_module}{$arg} |
1177
|
0
|
0
|
|
|
|
0
|
and $arg = $self->{_help_module}{$arg}; |
1178
|
0
|
0
|
|
|
|
0
|
if ( my $cmd = $self->_get_browser_command() ) { |
1179
|
0
|
0
|
|
|
|
0
|
my $kind = $arg =~ m/ - /smx ? 'release' : 'pod'; |
1180
|
0
|
|
|
|
|
0
|
$self->system( $cmd, |
1181
|
|
|
|
|
|
|
"https://metacpan.org/$kind/$arg" ); |
1182
|
|
|
|
|
|
|
} else { |
1183
|
|
|
|
|
|
|
|
1184
|
0
|
|
|
|
|
0
|
my $os_specific = "_help_$^O"; |
1185
|
0
|
0
|
|
|
|
0
|
if (__PACKAGE__->can ($os_specific)) { |
|
|
0
|
|
|
|
|
|
1186
|
0
|
|
|
|
|
0
|
return __PACKAGE__->$os_specific (); |
1187
|
|
|
|
|
|
|
} elsif ( load_package( 'Pod::Usage' ) ) { |
1188
|
0
|
|
|
|
|
0
|
my @ha; |
1189
|
0
|
0
|
|
|
|
0
|
if ( defined( my $path = find_package_pod( $arg ) ) ) { |
1190
|
0
|
|
|
|
|
0
|
push @ha, '-input' => $path; |
1191
|
|
|
|
|
|
|
} |
1192
|
0
|
|
|
|
|
0
|
my $stdout = $self->{frame}[-1]{localout}; |
1193
|
0
|
0
|
0
|
|
|
0
|
if (openhandle $stdout && !-t $stdout) { |
1194
|
0
|
|
|
|
|
0
|
push @ha, -output => $stdout; |
1195
|
|
|
|
|
|
|
} |
1196
|
|
|
|
|
|
|
Pod::Usage::pod2usage ( |
1197
|
0
|
|
|
|
|
0
|
-verbose => 2, -exitval => 'NOEXIT', @ha); |
1198
|
|
|
|
|
|
|
} else { |
1199
|
|
|
|
|
|
|
# This should never happen, since Pod::Usage is core |
1200
|
|
|
|
|
|
|
# since 5.6. On the other hand we have not declared it |
1201
|
|
|
|
|
|
|
# as a dependency, and some downstream packagers seem to |
1202
|
|
|
|
|
|
|
# think they know more than the author what should be in |
1203
|
|
|
|
|
|
|
# a package. |
1204
|
|
|
|
|
|
|
return <<'EOD' |
1205
|
|
|
|
|
|
|
No help available; Pod::Usage can not be loaded. |
1206
|
|
|
|
|
|
|
EOD |
1207
|
0
|
|
|
|
|
0
|
} |
1208
|
|
|
|
|
|
|
} |
1209
|
0
|
|
|
|
|
0
|
return; |
1210
|
20
|
|
|
20
|
|
13847
|
} |
|
20
|
|
|
|
|
52
|
|
|
20
|
|
|
|
|
91
|
|
1211
|
|
|
|
|
|
|
|
1212
|
|
|
|
|
|
|
# The call to this is generated dynamically above, and there is no way |
1213
|
|
|
|
|
|
|
# Perl::Critic can find it. |
1214
|
|
|
|
|
|
|
sub _help_MacOS { ## no critic (ProhibitUnusedPrivateSubroutines) |
1215
|
0
|
|
|
0
|
|
0
|
return <<'EOD'; |
1216
|
|
|
|
|
|
|
|
1217
|
|
|
|
|
|
|
Normally, we would display the documentation for the satpass2 |
1218
|
|
|
|
|
|
|
script here. But unfortunately this depends on the ability to |
1219
|
|
|
|
|
|
|
spawn the perldoc command, and we do not have this ability under |
1220
|
|
|
|
|
|
|
Mac OS 9 and earlier. You can find the same thing online at |
1221
|
|
|
|
|
|
|
https://metacpan.org/release/Astro-App-Satpass2 |
1222
|
|
|
|
|
|
|
|
1223
|
|
|
|
|
|
|
EOD |
1224
|
|
|
|
|
|
|
} |
1225
|
|
|
|
|
|
|
|
1226
|
|
|
|
|
|
|
{ |
1227
|
|
|
|
|
|
|
# This hash specifies the specific grammar passed to |
1228
|
|
|
|
|
|
|
# __infix_engine(). The keys are: |
1229
|
|
|
|
|
|
|
# {done} optional; called when parse is complete. |
1230
|
|
|
|
|
|
|
# {oper} defines operators. Values are hash refs with: |
1231
|
|
|
|
|
|
|
# {handler} code that handles operator; |
1232
|
|
|
|
|
|
|
# {validation} name of validation style (see {vld} below). |
1233
|
|
|
|
|
|
|
# {vld} defines operator validation. There must be a key for each |
1234
|
|
|
|
|
|
|
# distinct value of {oper}{$name}{validation}. |
1235
|
|
|
|
|
|
|
# NOTE WELL |
1236
|
|
|
|
|
|
|
# Because if() has the Tweak( -unsatisfied ) attribute, any |
1237
|
|
|
|
|
|
|
# operators that have side effects will need to be aware of whether |
1238
|
|
|
|
|
|
|
# they are running inside an unsatisfied if(). |
1239
|
|
|
|
|
|
|
my %define = ( |
1240
|
|
|
|
|
|
|
done => sub { |
1241
|
|
|
|
|
|
|
# my ( $self, $def, $ctx, $tokens ) = @_; |
1242
|
|
|
|
|
|
|
my ( $self, undef, $ctx ) = @_; |
1243
|
|
|
|
|
|
|
@{ $ctx } |
1244
|
|
|
|
|
|
|
and $self->wail( q );; |
1245
|
|
|
|
|
|
|
return; |
1246
|
|
|
|
|
|
|
}, |
1247
|
|
|
|
|
|
|
oper => { |
1248
|
|
|
|
|
|
|
'(' => { |
1249
|
|
|
|
|
|
|
handler => sub { |
1250
|
|
|
|
|
|
|
my ( $self, $def, $ctx, $tokens ) = @_; |
1251
|
|
|
|
|
|
|
my $want = delete $ctx->[-1]{want}; |
1252
|
|
|
|
|
|
|
defined $want |
1253
|
|
|
|
|
|
|
or $want = 1; |
1254
|
|
|
|
|
|
|
push @{ $ctx }, { |
1255
|
|
|
|
|
|
|
want => $want, |
1256
|
|
|
|
|
|
|
value => [], |
1257
|
|
|
|
|
|
|
}; |
1258
|
|
|
|
|
|
|
$ctx->[-2]{shortcut} |
1259
|
|
|
|
|
|
|
and $ctx->[1]{shortcut} = $ctx->[-2]{shortcut}; |
1260
|
|
|
|
|
|
|
my $depth = @{ $ctx }; |
1261
|
|
|
|
|
|
|
while ( $depth <= @{ $ctx } ) { |
1262
|
|
|
|
|
|
|
$self->_infix_engine_dispatch( $def, $ctx, $tokens ); |
1263
|
|
|
|
|
|
|
} |
1264
|
|
|
|
|
|
|
return; |
1265
|
|
|
|
|
|
|
}, |
1266
|
|
|
|
|
|
|
}, |
1267
|
|
|
|
|
|
|
')' => { |
1268
|
|
|
|
|
|
|
handler => sub { |
1269
|
|
|
|
|
|
|
# my ( $self, $def, $ctx, $tokens ) = @_; |
1270
|
|
|
|
|
|
|
my ( $self, undef, $ctx ) = @_; |
1271
|
|
|
|
|
|
|
@{ $ctx } |
1272
|
|
|
|
|
|
|
or $self->wail( 'Unpaired right parentheses' ); |
1273
|
|
|
|
|
|
|
$ctx->[-1]{want} == @{ $ctx->[-1]{value} } |
1274
|
|
|
|
|
|
|
or $self->wail( |
1275
|
|
|
|
|
|
|
"Expected $ctx->[-1]{want} value(s), got " . |
1276
|
|
|
|
|
|
|
scalar @{ $ctx->[-1]{value} } ); |
1277
|
|
|
|
|
|
|
push @{ $ctx->[-2]{value} }, @{ $ctx->[-1]{value} }; |
1278
|
|
|
|
|
|
|
pop @{ $ctx }; |
1279
|
|
|
|
|
|
|
return; |
1280
|
|
|
|
|
|
|
}, |
1281
|
|
|
|
|
|
|
}, |
1282
|
|
|
|
|
|
|
'-n' => { |
1283
|
|
|
|
|
|
|
handler => sub { |
1284
|
|
|
|
|
|
|
# my ( $self, $def, $ctx, $tokens ) = @_; |
1285
|
|
|
|
|
|
|
my ( undef, undef, $ctx, $tokens ) = @_; |
1286
|
|
|
|
|
|
|
my $v = shift @{ $tokens }; |
1287
|
|
|
|
|
|
|
defined $v |
1288
|
|
|
|
|
|
|
or $v = ''; |
1289
|
|
|
|
|
|
|
push @{ $ctx->[-1]{value} }, '' ne $v; |
1290
|
|
|
|
|
|
|
}, |
1291
|
|
|
|
|
|
|
validation => 'prefix', |
1292
|
|
|
|
|
|
|
}, |
1293
|
|
|
|
|
|
|
'-z' => { |
1294
|
|
|
|
|
|
|
handler => sub { |
1295
|
|
|
|
|
|
|
# my ( $self, $def, $ctx, $tokens ) = @_; |
1296
|
|
|
|
|
|
|
my ( undef, undef, $ctx, $tokens ) = @_; |
1297
|
|
|
|
|
|
|
my $v = shift @{ $tokens }; |
1298
|
|
|
|
|
|
|
defined $v |
1299
|
|
|
|
|
|
|
or $v = ''; |
1300
|
|
|
|
|
|
|
push @{ $ctx->[-1]{value} }, '' eq $v; |
1301
|
|
|
|
|
|
|
}, |
1302
|
|
|
|
|
|
|
validation => 'prefix', |
1303
|
|
|
|
|
|
|
}, |
1304
|
|
|
|
|
|
|
and => { |
1305
|
|
|
|
|
|
|
handler => sub { |
1306
|
|
|
|
|
|
|
my ( $self, $def, $ctx, $tokens ) = @_; |
1307
|
|
|
|
|
|
|
$ctx->[-1]{value}[-1] |
1308
|
|
|
|
|
|
|
or $ctx->[-1]{shortcut} = 1; |
1309
|
|
|
|
|
|
|
$self->_infix_engine_dispatch( $def, $ctx, $tokens ); |
1310
|
|
|
|
|
|
|
# For some reason the following has to be done in |
1311
|
|
|
|
|
|
|
# two statements, or both operands remain on the |
1312
|
|
|
|
|
|
|
# stack. |
1313
|
|
|
|
|
|
|
my $ro = pop @{ $ctx->[-1]{value} }; |
1314
|
|
|
|
|
|
|
$ctx->[-1]{value}[-1] &&= $ro |
1315
|
|
|
|
|
|
|
unless delete $ctx->[-1]{shortcut}; |
1316
|
|
|
|
|
|
|
return; |
1317
|
|
|
|
|
|
|
}, |
1318
|
|
|
|
|
|
|
validation => 'infix', |
1319
|
|
|
|
|
|
|
}, |
1320
|
|
|
|
|
|
|
attr => { |
1321
|
|
|
|
|
|
|
handler => sub { |
1322
|
|
|
|
|
|
|
# my ( $self, $def, $ctx, $tokens ) = @_; |
1323
|
|
|
|
|
|
|
my ( $self, undef, $ctx, $tokens ) = @_; |
1324
|
|
|
|
|
|
|
my $attr = shift @{ $tokens }; |
1325
|
|
|
|
|
|
|
my $val; |
1326
|
|
|
|
|
|
|
$ctx->[-1]{shortcut} |
1327
|
|
|
|
|
|
|
or $val = $self->_attribute_value( $attr ); |
1328
|
|
|
|
|
|
|
NULL_REF eq ref $val |
1329
|
|
|
|
|
|
|
and $self->wail( "No such attribute as '$attr'" ); |
1330
|
|
|
|
|
|
|
push @{ $ctx->[-1]{value} }, $val; |
1331
|
|
|
|
|
|
|
return; |
1332
|
|
|
|
|
|
|
}, |
1333
|
|
|
|
|
|
|
validation => 'prefix', |
1334
|
|
|
|
|
|
|
}, |
1335
|
|
|
|
|
|
|
env => { |
1336
|
|
|
|
|
|
|
handler => sub { |
1337
|
|
|
|
|
|
|
# my ( $self, $def, $ctx, $tokens ) = @_; |
1338
|
|
|
|
|
|
|
my ( undef, undef, $ctx, $tokens ) = @_; |
1339
|
|
|
|
|
|
|
my $name = shift @{ $tokens }; |
1340
|
|
|
|
|
|
|
my $val; |
1341
|
|
|
|
|
|
|
$ctx->[-1]{shortcut} |
1342
|
|
|
|
|
|
|
or $val = $ENV{$name}; |
1343
|
|
|
|
|
|
|
push @{ $ctx->[-1]{value} }, $val; |
1344
|
|
|
|
|
|
|
return; |
1345
|
|
|
|
|
|
|
}, |
1346
|
|
|
|
|
|
|
validation => 'prefix', |
1347
|
|
|
|
|
|
|
}, |
1348
|
|
|
|
|
|
|
loaded => { |
1349
|
|
|
|
|
|
|
handler => sub { |
1350
|
|
|
|
|
|
|
# my ( $self, $def, $ctx, $tokens ) = @_; |
1351
|
|
|
|
|
|
|
my ( $self, undef, $ctx, $tokens ) = @_; |
1352
|
|
|
|
|
|
|
my $name = shift @{ $tokens }; |
1353
|
|
|
|
|
|
|
my @loaded; |
1354
|
|
|
|
|
|
|
$ctx->[-1]{shortcut} |
1355
|
|
|
|
|
|
|
or @loaded = $self->__choose( |
1356
|
|
|
|
|
|
|
{ bodies => 1 }, |
1357
|
|
|
|
|
|
|
[ $name ], |
1358
|
|
|
|
|
|
|
); |
1359
|
|
|
|
|
|
|
push @{ $ctx->[-1]{value} }, scalar @loaded; |
1360
|
|
|
|
|
|
|
return; |
1361
|
|
|
|
|
|
|
}, |
1362
|
|
|
|
|
|
|
validation => 'prefix', |
1363
|
|
|
|
|
|
|
}, |
1364
|
|
|
|
|
|
|
not => { |
1365
|
|
|
|
|
|
|
handler => sub { |
1366
|
|
|
|
|
|
|
my ( $self, $def, $ctx, $tokens ) = @_; |
1367
|
|
|
|
|
|
|
$self->_infix_engine_dispatch( $def, $ctx, $tokens ); |
1368
|
|
|
|
|
|
|
$ctx->[-1]{value}[-1] = ! $ctx->[-1]{value}[-1]; |
1369
|
|
|
|
|
|
|
return; |
1370
|
|
|
|
|
|
|
}, |
1371
|
|
|
|
|
|
|
validation => 'prefix', |
1372
|
|
|
|
|
|
|
}, |
1373
|
|
|
|
|
|
|
or => { |
1374
|
|
|
|
|
|
|
handler => sub { |
1375
|
|
|
|
|
|
|
my ( $self, $def, $ctx, $tokens ) = @_; |
1376
|
|
|
|
|
|
|
$ctx->[-1]{value}[-1] |
1377
|
|
|
|
|
|
|
and $ctx->[-1]{shortcut} = 1; |
1378
|
|
|
|
|
|
|
$self->_infix_engine_dispatch( $def, $ctx, $tokens ); |
1379
|
|
|
|
|
|
|
# For some reason the following has to be done in |
1380
|
|
|
|
|
|
|
# two statements, or both operands remain on the |
1381
|
|
|
|
|
|
|
# stack. |
1382
|
|
|
|
|
|
|
my $ro = pop @{ $ctx->[-1]{value} }; |
1383
|
|
|
|
|
|
|
$ctx->[-1]{value}[-1] ||= $ro |
1384
|
|
|
|
|
|
|
unless delete $ctx->[-1]{shortcut}; |
1385
|
|
|
|
|
|
|
return; |
1386
|
|
|
|
|
|
|
}, |
1387
|
|
|
|
|
|
|
validation => 'infix', |
1388
|
|
|
|
|
|
|
}, |
1389
|
|
|
|
|
|
|
os => { |
1390
|
|
|
|
|
|
|
handler => sub { |
1391
|
|
|
|
|
|
|
# my ( $self, $def, $ctx, $tokens ) = @_; |
1392
|
|
|
|
|
|
|
my ( undef, undef, $ctx, $tokens ) = @_; |
1393
|
|
|
|
|
|
|
my $re = qr< \A \Q$^O\E \z >smxi; |
1394
|
|
|
|
|
|
|
my $rslt = 0; |
1395
|
|
|
|
|
|
|
my $name = shift @{ $tokens }; |
1396
|
|
|
|
|
|
|
unless ( $ctx->[-1]{shortcut} ) { |
1397
|
|
|
|
|
|
|
foreach my $os ( split qr< [|] >smx, $name ) { |
1398
|
|
|
|
|
|
|
$os =~ $re |
1399
|
|
|
|
|
|
|
or next; |
1400
|
|
|
|
|
|
|
$rslt = 1; |
1401
|
|
|
|
|
|
|
last; |
1402
|
|
|
|
|
|
|
} |
1403
|
|
|
|
|
|
|
} |
1404
|
|
|
|
|
|
|
push @{ $ctx->[-1]{value} }, $rslt; |
1405
|
|
|
|
|
|
|
return; |
1406
|
|
|
|
|
|
|
}, |
1407
|
|
|
|
|
|
|
validation => 'prefix', |
1408
|
|
|
|
|
|
|
}, |
1409
|
|
|
|
|
|
|
then => { |
1410
|
|
|
|
|
|
|
handler => sub { |
1411
|
|
|
|
|
|
|
# my ( $self, $def, $ctx, $tokens ) = @_; |
1412
|
|
|
|
|
|
|
my ( $self, undef, $ctx, $tokens ) = @_; |
1413
|
|
|
|
|
|
|
1 == @{ $ctx } |
1414
|
|
|
|
|
|
|
or $self->wail( 'Unclosed left parentheses' ); |
1415
|
|
|
|
|
|
|
my $last = pop @{ $ctx }; |
1416
|
|
|
|
|
|
|
my @arg = splice @{ $tokens }; |
1417
|
|
|
|
|
|
|
if ( $last->{dispatch} ) { |
1418
|
|
|
|
|
|
|
$self->_dispatch_check( if => $arg[0] ); |
1419
|
|
|
|
|
|
|
$self->_frame_push( if => [], { |
1420
|
|
|
|
|
|
|
condition => $last->{value}[-1], |
1421
|
|
|
|
|
|
|
}, |
1422
|
|
|
|
|
|
|
); |
1423
|
|
|
|
|
|
|
$self->_add_post_dispatch( sub { |
1424
|
|
|
|
|
|
|
$self->_frame_pop( if => undef ); |
1425
|
|
|
|
|
|
|
}, |
1426
|
|
|
|
|
|
|
); |
1427
|
|
|
|
|
|
|
return $self->dispatch( @arg ); |
1428
|
|
|
|
|
|
|
} else { |
1429
|
|
|
|
|
|
|
$self->_twiddle_condition( $last->{value}[-1] ); |
1430
|
|
|
|
|
|
|
} |
1431
|
|
|
|
|
|
|
}, |
1432
|
|
|
|
|
|
|
validation => 'terminal', |
1433
|
|
|
|
|
|
|
}, |
1434
|
|
|
|
|
|
|
}, |
1435
|
|
|
|
|
|
|
val => sub { |
1436
|
|
|
|
|
|
|
# my ( $self, $def, $ctx, $tkn, $tokens ) = @_; |
1437
|
|
|
|
|
|
|
my ( undef, undef, $ctx, $tkn ) = @_; |
1438
|
|
|
|
|
|
|
push @{ $ctx->[-1]{value} }, $tkn; |
1439
|
|
|
|
|
|
|
return; |
1440
|
|
|
|
|
|
|
}, |
1441
|
|
|
|
|
|
|
vld => { |
1442
|
|
|
|
|
|
|
infix => sub { |
1443
|
|
|
|
|
|
|
# my ( $self, $def, $ctx, $tkn, $tokens ) = @_; |
1444
|
|
|
|
|
|
|
my ( $self, undef, $ctx, $tkn, $tokens ) = @_; |
1445
|
|
|
|
|
|
|
@{ $ctx->[-1]{value} } |
1446
|
|
|
|
|
|
|
or $self->wail( "'$tkn' requires a left argument" ); |
1447
|
|
|
|
|
|
|
@{ $tokens } |
1448
|
|
|
|
|
|
|
or $self->wail( "'$tkn' requires a right argument" ); |
1449
|
|
|
|
|
|
|
return; |
1450
|
|
|
|
|
|
|
}, |
1451
|
|
|
|
|
|
|
prefix => sub { |
1452
|
|
|
|
|
|
|
# my ( $self, $def, $ctx, $tkn, $tokens ) = @_; |
1453
|
|
|
|
|
|
|
my ( $self, undef, undef, $tkn, $tokens ) = @_; |
1454
|
|
|
|
|
|
|
@{ $tokens } |
1455
|
|
|
|
|
|
|
or $self->wail( "'$tkn' requires an argument" ); |
1456
|
|
|
|
|
|
|
return; |
1457
|
|
|
|
|
|
|
}, |
1458
|
|
|
|
|
|
|
terminal => sub { |
1459
|
|
|
|
|
|
|
# my ( $self, $def, $ctx, $tkn, $tokens ) = @_; |
1460
|
|
|
|
|
|
|
my ( $self, undef, $ctx, $tkn, $tokens ) = @_; |
1461
|
|
|
|
|
|
|
@{ $ctx->[-1]{value} } |
1462
|
|
|
|
|
|
|
or $self->wail( "'$tkn' requires a left argument" ); |
1463
|
|
|
|
|
|
|
if ( $ctx->[-1]{dispatch} ) { |
1464
|
|
|
|
|
|
|
@{ $tokens } |
1465
|
|
|
|
|
|
|
or $self->wail( "Command required after '$tkn'" ); |
1466
|
|
|
|
|
|
|
} else { |
1467
|
|
|
|
|
|
|
@{ $tokens } |
1468
|
|
|
|
|
|
|
and $self->wail( "Command not allowed after '$tkn'" ); |
1469
|
|
|
|
|
|
|
} |
1470
|
|
|
|
|
|
|
return; |
1471
|
|
|
|
|
|
|
} |
1472
|
|
|
|
|
|
|
}, |
1473
|
|
|
|
|
|
|
); |
1474
|
|
|
|
|
|
|
|
1475
|
|
|
|
|
|
|
sub elsif : method Verb() Tweak( -unsatisfied ) { ## no critic (ProhibitBuiltInHomonyms) |
1476
|
2
|
|
|
2
|
1
|
20
|
my ( $self, @args ) = @_; |
1477
|
|
|
|
|
|
|
@args |
1478
|
2
|
50
|
|
|
|
8
|
or $self->wail( 'Arguments required' ); |
1479
|
|
|
|
|
|
|
|
1480
|
2
|
|
|
|
|
33
|
@{ $self->{frame} } > 1 |
1481
|
|
|
|
|
|
|
and 'begin' eq $self->{frame}[-1]{type} |
1482
|
|
|
|
|
|
|
and 'if' eq $self->{frame}[-2]{type} |
1483
|
2
|
50
|
33
|
|
|
5
|
or $self->wail( 'Elsif without if ... then begin' ); |
|
|
|
33
|
|
|
|
|
1484
|
|
|
|
|
|
|
|
1485
|
2
|
|
|
|
|
9
|
my @ctx = ( { |
1486
|
|
|
|
|
|
|
dispatch => 0, |
1487
|
|
|
|
|
|
|
value => [], |
1488
|
|
|
|
|
|
|
} ); |
1489
|
|
|
|
|
|
|
|
1490
|
|
|
|
|
|
|
# If any previous if() or elsif() evaluates true, we do not |
1491
|
|
|
|
|
|
|
# evaluate subsequent elsif() calls. |
1492
|
|
|
|
|
|
|
$self->{frame}[-2]{condition} |
1493
|
2
|
50
|
|
|
|
8
|
and return; |
1494
|
2
|
|
|
|
|
6
|
return $self->__infix_engine( \%define, \@ctx, @args ); |
1495
|
20
|
|
|
20
|
|
43411
|
} |
|
20
|
|
|
|
|
69
|
|
|
20
|
|
|
|
|
137
|
|
1496
|
|
|
|
|
|
|
|
1497
|
|
|
|
|
|
|
sub if : method Verb() Tweak( -unsatisfied ) { ## no critic (ProhibitBuiltInHomonyms) |
1498
|
22
|
|
|
22
|
1
|
76
|
my ( $self, @args ) = @_; |
1499
|
|
|
|
|
|
|
@args |
1500
|
22
|
50
|
|
|
|
54
|
or $self->wail( 'Arguments required' ); |
1501
|
22
|
|
|
|
|
87
|
my @ctx = ( { |
1502
|
|
|
|
|
|
|
dispatch => 1, |
1503
|
|
|
|
|
|
|
value => [], |
1504
|
|
|
|
|
|
|
} ); |
1505
|
22
|
|
|
|
|
63
|
return $self->__infix_engine( \%define, \@ctx, @args ); |
1506
|
20
|
|
|
20
|
|
6435
|
} |
|
20
|
|
|
|
|
59
|
|
|
20
|
|
|
|
|
107
|
|
1507
|
|
|
|
|
|
|
} |
1508
|
|
|
|
|
|
|
|
1509
|
|
|
|
|
|
|
sub init { |
1510
|
0
|
|
|
0
|
1
|
0
|
my ( $self, @args ) = @_; |
1511
|
|
|
|
|
|
|
|
1512
|
0
|
0
|
|
|
|
0
|
my $opt = HASH_REF eq ref $args[0] ? shift @args : {}; |
1513
|
0
|
|
|
|
|
0
|
my $init_file = shift @args; |
1514
|
|
|
|
|
|
|
|
1515
|
0
|
|
|
|
|
0
|
$self->{initfile} = undef; |
1516
|
|
|
|
|
|
|
|
1517
|
0
|
0
|
|
|
|
0
|
foreach ( |
1518
|
|
|
|
|
|
|
defined $init_file ? ( |
1519
|
|
|
|
|
|
|
sub { |
1520
|
|
|
|
|
|
|
# A missing init file is only an error if it was |
1521
|
|
|
|
|
|
|
# specified explicitly. |
1522
|
0
|
0
|
0
|
0
|
|
0
|
-e $init_file |
1523
|
|
|
|
|
|
|
and not -d _ |
1524
|
|
|
|
|
|
|
or $self->wail( |
1525
|
|
|
|
|
|
|
"Initialization file $init_file not found, or is a directory" |
1526
|
|
|
|
|
|
|
); |
1527
|
|
|
|
|
|
|
return ( $init_file, $opt->{level1} ) |
1528
|
0
|
|
|
|
|
0
|
}, |
1529
|
|
|
|
|
|
|
) : ( |
1530
|
0
|
|
|
0
|
|
0
|
sub { return $ENV{SATPASS2INI} }, |
1531
|
0
|
|
|
0
|
|
0
|
sub { $self->initfile( { quiet => 1 } ) }, |
1532
|
0
|
|
|
0
|
|
0
|
sub { return ( $ENV{SATPASSINI}, 1 ) }, |
1533
|
|
|
|
|
|
|
\&_init_file_01, |
1534
|
|
|
|
|
|
|
) |
1535
|
|
|
|
|
|
|
) { |
1536
|
|
|
|
|
|
|
|
1537
|
0
|
|
|
|
|
0
|
my ( $fn, $level1 ) = $_->($self); |
1538
|
0
|
0
|
|
|
|
0
|
my $reader = $self->_file_reader( $fn, { optional => 1 } ) |
1539
|
|
|
|
|
|
|
or next; |
1540
|
0
|
|
|
|
|
0
|
$self->{initfile} = $fn; |
1541
|
0
|
|
|
|
|
0
|
return $self->source( { level1 => $level1 }, $reader ); |
1542
|
|
|
|
|
|
|
|
1543
|
|
|
|
|
|
|
} |
1544
|
|
|
|
|
|
|
|
1545
|
0
|
|
|
|
|
0
|
return; |
1546
|
|
|
|
|
|
|
} |
1547
|
|
|
|
|
|
|
|
1548
|
|
|
|
|
|
|
sub initfile : Verb( create-directory! quiet! ) { |
1549
|
0
|
|
|
0
|
1
|
0
|
my ( $self, $opt ) = __arguments( @_ ); # @args unused |
1550
|
|
|
|
|
|
|
|
1551
|
|
|
|
|
|
|
my $init_dir = my_dist_config( |
1552
|
0
|
|
|
|
|
0
|
{ create => $opt->{'create-directory'} } ); |
1553
|
|
|
|
|
|
|
|
1554
|
|
|
|
|
|
|
defined $init_dir |
1555
|
0
|
0
|
|
|
|
0
|
or do { |
1556
|
0
|
0
|
|
|
|
0
|
$opt->{quiet} and return; |
1557
|
0
|
|
|
|
|
0
|
$self->wail( |
1558
|
|
|
|
|
|
|
'Init file directory not found' ); |
1559
|
|
|
|
|
|
|
}; |
1560
|
|
|
|
|
|
|
|
1561
|
0
|
|
|
|
|
0
|
return File::Spec->catfile( $init_dir, 'satpass2rc' ); |
1562
|
20
|
|
|
20
|
|
12651
|
} |
|
20
|
|
|
|
|
1253
|
|
|
20
|
|
|
|
|
1458
|
|
1563
|
|
|
|
|
|
|
|
1564
|
|
|
|
|
|
|
sub _in_unsatisfied_if { |
1565
|
290
|
|
|
290
|
|
555
|
my ( $self ) = @_; |
1566
|
290
|
50
|
|
|
|
405
|
return @{ $self->{frame} } ? $self->{frame}[-1]{unsatisfied_if} : 0; |
|
290
|
|
|
|
|
1132
|
|
1567
|
|
|
|
|
|
|
} |
1568
|
|
|
|
|
|
|
|
1569
|
|
|
|
|
|
|
# This is a generalized infix expression engine. It does not implement |
1570
|
|
|
|
|
|
|
# operator precedence and is therefore very small. The arguments are: |
1571
|
|
|
|
|
|
|
# - $self is the invocant, which must be an |
1572
|
|
|
|
|
|
|
# Astro::App::Satpass2::Copier. |
1573
|
|
|
|
|
|
|
# - $def is the hash that defines the grammar. This provides the |
1574
|
|
|
|
|
|
|
# following keys: |
1575
|
|
|
|
|
|
|
# {done} is an optional code reference. If present, the code |
1576
|
|
|
|
|
|
|
# reference is called once the parse is complete, and passed |
1577
|
|
|
|
|
|
|
# ( $self, $def, $ctx, \@tokens ). It returns nothing. The intent |
1578
|
|
|
|
|
|
|
# is to throw an exception if the parse is incomplete. |
1579
|
|
|
|
|
|
|
# {oper} defines the operators. This is a hash keyed by the literal |
1580
|
|
|
|
|
|
|
# operator (i.e. '+' to implement a '+' operator), and having the |
1581
|
|
|
|
|
|
|
# following values: |
1582
|
|
|
|
|
|
|
# {handler} is a required code reference, which implements the |
1583
|
|
|
|
|
|
|
# operator. It is passed ( $self, $def, $ctx, \@tokens ). The |
1584
|
|
|
|
|
|
|
# @tokens do not include the operator itself. |
1585
|
|
|
|
|
|
|
# {validation} is an optional validation specification. If |
1586
|
|
|
|
|
|
|
# present it is a key in the {vld} (see below). |
1587
|
|
|
|
|
|
|
# {val} is an optional code reference. If present, it is called if a |
1588
|
|
|
|
|
|
|
# token is not recognized as an operator, and passed ( $self, |
1589
|
|
|
|
|
|
|
# $def, $ctx, \@tokens ). The @tokens include the unrecognized |
1590
|
|
|
|
|
|
|
# token, which is presumed to be a value, and must be removed |
1591
|
|
|
|
|
|
|
# from @tokens. |
1592
|
|
|
|
|
|
|
# {vld} is a hash of validators. The keys are values in the |
1593
|
|
|
|
|
|
|
# {validation} key documented under {oper} (above), and the |
1594
|
|
|
|
|
|
|
# values are code references which are called with ( $self, $ctx, |
1595
|
|
|
|
|
|
|
# $tkn, \@tokens ) where $tkn is the token being validated, and |
1596
|
|
|
|
|
|
|
# @tokens is the rest of the tokens. This hash must exist if the |
1597
|
|
|
|
|
|
|
# {validation} key is used in {oper}; otherwise it is optional. |
1598
|
|
|
|
|
|
|
# - $ctx is context for the operations. It is not used by the engine |
1599
|
|
|
|
|
|
|
# itself, but the individual operator code will need to use it as |
1600
|
|
|
|
|
|
|
# context for the parse. See if() for an example. |
1601
|
|
|
|
|
|
|
# - @tokens are the tokens to be evaluated by the engine. |
1602
|
|
|
|
|
|
|
sub __infix_engine { |
1603
|
24
|
|
|
24
|
|
74
|
my ( $self, $def, $ctx, @tokens ) = @_; |
1604
|
|
|
|
|
|
|
@tokens |
1605
|
24
|
50
|
|
|
|
47
|
or $self->wail( 'Nothing to compute' ); |
1606
|
24
|
|
|
|
|
35
|
my $rslt; |
1607
|
24
|
|
|
|
|
52
|
while ( @tokens ) { |
1608
|
50
|
|
|
|
|
163
|
$rslt = $self->_infix_engine_dispatch( $def, $ctx, \@tokens ); |
1609
|
|
|
|
|
|
|
} |
1610
|
|
|
|
|
|
|
$def->{done} |
1611
|
24
|
50
|
|
|
|
99
|
and $def->{done}->( $self, $def, $ctx, \@tokens ); |
1612
|
24
|
|
|
|
|
82
|
return $rslt; |
1613
|
|
|
|
|
|
|
} |
1614
|
|
|
|
|
|
|
|
1615
|
|
|
|
|
|
|
sub _infix_engine_dispatch { |
1616
|
61
|
|
|
61
|
|
111
|
my ( $self, $def, $ctx, $tokens ) = @_; |
1617
|
61
|
50
|
|
|
|
89
|
@{ $tokens } |
|
61
|
|
|
|
|
118
|
|
1618
|
|
|
|
|
|
|
or return; |
1619
|
61
|
|
|
|
|
97
|
my $tkn = shift @{ $tokens }; |
|
61
|
|
|
|
|
103
|
|
1620
|
61
|
100
|
|
|
|
205
|
if ( my $info = $def->{oper}{$tkn} ) { |
|
|
50
|
|
|
|
|
|
1621
|
|
|
|
|
|
|
$info->{validation} |
1622
|
57
|
100
|
|
|
|
256
|
and $def->{vld}{ $info->{validation} }->( |
1623
|
|
|
|
|
|
|
$self, $def, $ctx, $tkn, $tokens ); |
1624
|
57
|
|
|
|
|
148
|
return $info->{handler}->( $self, $def, $ctx, $tokens ); |
1625
|
|
|
|
|
|
|
} elsif ( $def->{val} ) { |
1626
|
4
|
|
|
|
|
24
|
return $def->{val}->( $self, $def, $ctx, $tkn, $tokens ); |
1627
|
|
|
|
|
|
|
} else { |
1628
|
0
|
|
|
|
|
0
|
$self->wail( "Unrecognized token '$tkn'" ); |
1629
|
|
|
|
|
|
|
} |
1630
|
0
|
|
|
|
|
0
|
return; # We can't get here, but Perl::Critic does not know this. |
1631
|
|
|
|
|
|
|
} |
1632
|
|
|
|
|
|
|
|
1633
|
|
|
|
|
|
|
# $file_name = _init_file_01() |
1634
|
|
|
|
|
|
|
# |
1635
|
|
|
|
|
|
|
# This subroutine returns the first alternate init file name, |
1636
|
|
|
|
|
|
|
# which is the standard name for the Astro-satpass 'satpass' |
1637
|
|
|
|
|
|
|
# script. If called in list context it returns not only the name, |
1638
|
|
|
|
|
|
|
# but a 1 to tell the caller this is a 'level1' file. |
1639
|
|
|
|
|
|
|
|
1640
|
|
|
|
|
|
|
sub _init_file_01 { |
1641
|
0
|
0
|
0
|
0
|
|
0
|
my $inifn = $^O eq 'MSWin32' || $^O eq 'VMS' || $^O eq 'MacOS' ? |
1642
|
|
|
|
|
|
|
'satpass.ini' : '.satpass'; |
1643
|
|
|
|
|
|
|
my $inifile = $^O eq 'VMS' ? "SYS\$LOGIN:$inifn" : |
1644
|
|
|
|
|
|
|
$^O eq 'MacOS' ? $inifn : |
1645
|
|
|
|
|
|
|
$ENV{HOME} ? "$ENV{HOME}/$inifn" : |
1646
|
|
|
|
|
|
|
$ENV{LOGDIR} ? "$ENV{LOGDIR}/$inifn" : |
1647
|
0
|
0
|
|
|
|
0
|
$ENV{USERPROFILE} ? "$ENV{USERPROFILE}" : undef; |
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
1648
|
0
|
0
|
|
|
|
0
|
return wantarray ? ( $inifile, 1 ) : $inifile; |
1649
|
|
|
|
|
|
|
} |
1650
|
|
|
|
|
|
|
|
1651
|
|
|
|
|
|
|
sub list : Verb( choose=s@ ) { |
1652
|
7
|
|
|
7
|
1
|
96
|
my ( $self, $opt, @args ) = __arguments( @_ ); |
1653
|
|
|
|
|
|
|
|
1654
|
|
|
|
|
|
|
@args |
1655
|
|
|
|
|
|
|
and not $opt->{choose} |
1656
|
7
|
50
|
33
|
|
|
61
|
and $opt->{choose} = \@args; |
1657
|
7
|
|
|
|
|
83
|
my @bodies = $self->__choose( $opt->{choose}, $self->{bodies} ); |
1658
|
|
|
|
|
|
|
|
1659
|
|
|
|
|
|
|
@bodies |
1660
|
7
|
100
|
|
|
|
96
|
and return $self->__format_data( |
1661
|
|
|
|
|
|
|
list => \@bodies, $opt ); |
1662
|
|
|
|
|
|
|
|
1663
|
|
|
|
|
|
|
$self->{warn_on_empty} |
1664
|
2
|
50
|
|
|
|
17
|
and $self->whinge( 'The observing list is empty' ); |
1665
|
|
|
|
|
|
|
|
1666
|
2
|
|
|
|
|
8
|
return; |
1667
|
20
|
|
|
20
|
|
19766
|
} |
|
20
|
|
|
|
|
1247
|
|
|
20
|
|
|
|
|
1305
|
|
1668
|
|
|
|
|
|
|
|
1669
|
|
|
|
|
|
|
sub load : Verb( verbose! ) { |
1670
|
6
|
|
|
6
|
1
|
45
|
my ( $self, $opt, @names ) = __arguments( @_ ); |
1671
|
6
|
50
|
|
|
|
49
|
@names or $self->wail( 'No file names specified' ); |
1672
|
|
|
|
|
|
|
|
1673
|
6
|
|
|
|
|
38
|
my $attrs = { |
1674
|
|
|
|
|
|
|
illum => $self->get( 'illum' ), |
1675
|
|
|
|
|
|
|
model => $self->get( 'model' ), |
1676
|
|
|
|
|
|
|
sun => $self->_sky_object( 'sun' ), |
1677
|
|
|
|
|
|
|
}; |
1678
|
|
|
|
|
|
|
|
1679
|
6
|
|
|
|
|
681
|
foreach my $fn ( @names ) { |
1680
|
6
|
50
|
|
|
|
24
|
$opt->{verbose} and warn "Loading $fn\n"; |
1681
|
6
|
|
|
|
|
51
|
my $data = $self->_file_reader( $fn, { glob => 1 } ); |
1682
|
5
|
|
|
|
|
329
|
$self->__add_to_observing_list( |
1683
|
|
|
|
|
|
|
Astro::Coord::ECI::TLE->parse( $attrs, $data ) ); |
1684
|
|
|
|
|
|
|
} |
1685
|
5
|
|
|
|
|
40
|
return; |
1686
|
20
|
|
|
20
|
|
7565
|
} |
|
20
|
|
|
|
|
57
|
|
|
20
|
|
|
|
|
1212
|
|
1687
|
|
|
|
|
|
|
|
1688
|
|
|
|
|
|
|
sub localize : Verb( all|except! ) { |
1689
|
1
|
|
|
1
|
1
|
7
|
my ( $self, $opt, @args ) = __arguments( @_ ); |
1690
|
|
|
|
|
|
|
|
1691
|
1
|
|
|
|
|
5
|
foreach my $name ( @args ) { |
1692
|
2
|
|
|
|
|
6
|
$self->_attribute_exists( $name ); |
1693
|
|
|
|
|
|
|
} |
1694
|
|
|
|
|
|
|
|
1695
|
1
|
50
|
|
|
|
8
|
if ( $opt->{all} ) { |
1696
|
0
|
|
|
|
|
0
|
my %except = map { $_ => 1 } @args; |
|
0
|
|
|
|
|
0
|
|
1697
|
0
|
|
|
|
|
0
|
@args = grep { ! $except{$_} } sort keys %mutator; |
|
0
|
|
|
|
|
0
|
|
1698
|
|
|
|
|
|
|
} |
1699
|
|
|
|
|
|
|
|
1700
|
1
|
|
|
|
|
3
|
foreach my $name ( @args ) { |
1701
|
2
|
|
|
|
|
7
|
$self->_localize( $name ); |
1702
|
|
|
|
|
|
|
} |
1703
|
|
|
|
|
|
|
|
1704
|
1
|
|
|
|
|
7
|
return; |
1705
|
20
|
|
|
20
|
|
11941
|
} |
|
20
|
|
|
|
|
59
|
|
|
20
|
|
|
|
|
1341
|
|
1706
|
|
|
|
|
|
|
|
1707
|
|
|
|
|
|
|
sub _localize { |
1708
|
2
|
|
|
2
|
|
5
|
my ( $self, $key ) = @_; |
1709
|
|
|
|
|
|
|
|
1710
|
|
|
|
|
|
|
my $val = exists $self->{$key} ? |
1711
|
2
|
50
|
|
|
|
9
|
$self->{$key} : |
1712
|
|
|
|
|
|
|
$self->get( $key ); |
1713
|
2
|
50
|
33
|
|
|
11
|
my $clone = ( blessed( $val ) && $val->can( 'clone' ) ) ? |
|
|
50
|
|
|
|
|
|
1714
|
|
|
|
|
|
|
$val->clone() : |
1715
|
|
|
|
|
|
|
ref $val ? Clone::clone( $val ) : $val; |
1716
|
|
|
|
|
|
|
|
1717
|
2
|
|
|
|
|
7
|
$self->{frame}[-1]{local}{$key} = $val; |
1718
|
2
|
50
|
|
|
|
4
|
if ( exists $self->{$key} ) { |
1719
|
2
|
|
|
|
|
6
|
$self->{$key} = $clone; |
1720
|
|
|
|
|
|
|
} else { |
1721
|
0
|
|
|
|
|
0
|
$self->set( $key => $clone ); |
1722
|
|
|
|
|
|
|
} |
1723
|
|
|
|
|
|
|
|
1724
|
2
|
|
|
|
|
4
|
return; |
1725
|
|
|
|
|
|
|
} |
1726
|
|
|
|
|
|
|
|
1727
|
|
|
|
|
|
|
sub location : Verb( dump! ) { |
1728
|
3
|
|
|
3
|
1
|
26
|
my ( $self, $opt ) = __arguments( @_ ); |
1729
|
3
|
|
|
|
|
48
|
return $self->__format_data( |
1730
|
|
|
|
|
|
|
location => $self->station(), $opt ); |
1731
|
20
|
|
|
20
|
|
7445
|
} |
|
20
|
|
|
|
|
1323
|
|
|
20
|
|
|
|
|
1299
|
|
1732
|
|
|
|
|
|
|
|
1733
|
|
|
|
|
|
|
{ |
1734
|
|
|
|
|
|
|
|
1735
|
|
|
|
|
|
|
# TODO the %mac_cmd hash is only needed for level1 compatibility. |
1736
|
|
|
|
|
|
|
# Once that goes away, it can too PROVIDED we also drop the |
1737
|
|
|
|
|
|
|
# subcommand defaulting functionality. |
1738
|
|
|
|
|
|
|
# Subcommand defaulting dropped 2021-09-20 unless explicitly level1, |
1739
|
|
|
|
|
|
|
# after I discovered that my init file defined an unwanted macro |
1740
|
|
|
|
|
|
|
# when I mistyped 'define' as 'defined'. |
1741
|
|
|
|
|
|
|
my %mac_cmd; |
1742
|
|
|
|
|
|
|
{ |
1743
|
|
|
|
|
|
|
my $stb = __PACKAGE__ . '::'; |
1744
|
|
|
|
|
|
|
my @cmdnam; |
1745
|
|
|
|
|
|
|
{ |
1746
|
20
|
|
|
20
|
|
5398
|
no strict qw{ refs }; |
|
20
|
|
|
|
|
46
|
|
|
20
|
|
|
|
|
6728
|
|
1747
|
|
|
|
|
|
|
foreach my $entry ( keys %{ $stb } ) { |
1748
|
|
|
|
|
|
|
$entry =~ m/ \A _macro_sub_ ( \w+ ) /smx |
1749
|
|
|
|
|
|
|
or next; |
1750
|
|
|
|
|
|
|
# Strictly speaking I should make sure the {CODE} slot |
1751
|
|
|
|
|
|
|
# is occupied here. |
1752
|
|
|
|
|
|
|
push @cmdnam, $1; |
1753
|
|
|
|
|
|
|
} |
1754
|
|
|
|
|
|
|
} |
1755
|
|
|
|
|
|
|
my %abbr = abbrev(@cmdnam); |
1756
|
|
|
|
|
|
|
foreach (keys %abbr) { |
1757
|
|
|
|
|
|
|
$mac_cmd{'-' . $_} = $abbr{$_}; |
1758
|
|
|
|
|
|
|
} |
1759
|
|
|
|
|
|
|
foreach (@cmdnam) { |
1760
|
|
|
|
|
|
|
$mac_cmd{$_} = $_; |
1761
|
|
|
|
|
|
|
} |
1762
|
|
|
|
|
|
|
} |
1763
|
|
|
|
|
|
|
|
1764
|
|
|
|
|
|
|
# NOTE that we must not define command options here, but on the |
1765
|
|
|
|
|
|
|
# individual _macro_sub_* methods. Or at least we must not define |
1766
|
|
|
|
|
|
|
# any command options here that get passed to the _macro_sub_* |
1767
|
|
|
|
|
|
|
# methods. |
1768
|
|
|
|
|
|
|
sub macro : Verb() Tweak( -completion _readline_complete_subcommand ) { |
1769
|
29
|
|
|
29
|
1
|
99
|
my ( $self, undef, @args ) = __arguments( @_ ); # $opt unused |
1770
|
29
|
|
|
|
|
72
|
my $cmd; |
1771
|
29
|
50
|
|
|
|
107
|
if (!@args) { |
|
|
100
|
|
|
|
|
|
1772
|
0
|
|
|
|
|
0
|
$cmd = 'brief'; |
1773
|
|
|
|
|
|
|
} elsif ( $self->{frame}[-1]{level1} ) { |
1774
|
8
|
50
|
|
|
|
33
|
if ($mac_cmd{$args[0]}) { |
|
|
50
|
|
|
|
|
|
1775
|
0
|
|
|
|
|
0
|
$cmd = $mac_cmd{shift @args}; |
1776
|
|
|
|
|
|
|
} elsif (@args > 1) { |
1777
|
8
|
|
|
|
|
13
|
$cmd = 'define'; |
1778
|
|
|
|
|
|
|
} else { |
1779
|
0
|
|
|
|
|
0
|
$cmd = 'list'; |
1780
|
|
|
|
|
|
|
} |
1781
|
|
|
|
|
|
|
} else { |
1782
|
21
|
50
|
|
|
|
96
|
defined( $cmd = $mac_cmd{ $args[0] } ) |
1783
|
|
|
|
|
|
|
or $cmd = $args[0]; |
1784
|
21
|
|
|
|
|
42
|
shift @args; |
1785
|
|
|
|
|
|
|
} |
1786
|
|
|
|
|
|
|
|
1787
|
29
|
50
|
|
|
|
154
|
my $code = $self->can( "_macro_sub_$cmd" ) |
1788
|
|
|
|
|
|
|
or $self->wail( "Subcommand '$cmd' unknown" ); |
1789
|
29
|
|
|
|
|
103
|
return $code->( $self, @args ); |
1790
|
20
|
|
|
20
|
|
157
|
} |
|
20
|
|
|
|
|
54
|
|
|
20
|
|
|
|
|
97
|
|
1791
|
|
|
|
|
|
|
} |
1792
|
|
|
|
|
|
|
|
1793
|
|
|
|
|
|
|
# Calls to the following _macro_sub_... methods are generated dynamically |
1794
|
|
|
|
|
|
|
# above, so there is no way Perl::Critic can find them. |
1795
|
|
|
|
|
|
|
sub _macro_sub_brief : Verb() Tweak( -completion _macro_list_complete ) { ## no critic (ProhibitUnusedPrivateSubroutines) |
1796
|
3
|
|
|
3
|
|
10
|
my ( $self, undef, @args ) = __arguments( @_ ); |
1797
|
3
|
|
|
|
|
15
|
my $output; |
1798
|
3
|
50
|
|
|
|
10
|
foreach my $name (sort @args ? @args : keys %{$self->{macro}}) { |
|
3
|
|
|
|
|
14
|
|
1799
|
1
|
50
|
|
|
|
8
|
$self->{macro}{$name} and $output .= $name . "\n"; |
1800
|
|
|
|
|
|
|
} |
1801
|
3
|
|
|
|
|
11
|
return $output; |
1802
|
20
|
|
|
20
|
|
6860
|
} |
|
20
|
|
|
|
|
57
|
|
|
20
|
|
|
|
|
106
|
|
1803
|
|
|
|
|
|
|
|
1804
|
|
|
|
|
|
|
sub _macro_sub_define : Verb( completion=s@ ) { ## no critic (ProhibitUnusedPrivateSubroutines) |
1805
|
16
|
|
|
16
|
|
53
|
my ( $self, $opt, $name, @args ) = __arguments( @_ ); |
1806
|
16
|
|
|
|
|
43
|
my $output; |
1807
|
16
|
50
|
|
|
|
39
|
defined $name |
1808
|
|
|
|
|
|
|
or return $self->__wail( 'You must provide a name for the macro' ); |
1809
|
|
|
|
|
|
|
@args |
1810
|
16
|
50
|
|
|
|
38
|
or return $self->__wail( 'You must provide a definition for the macro' ); |
1811
|
|
|
|
|
|
|
|
1812
|
16
|
50
|
33
|
|
|
110
|
$name !~ m/ \W /smx |
1813
|
|
|
|
|
|
|
and $name !~ m/ \A _ /smx |
1814
|
|
|
|
|
|
|
or return $self->__wail("Invalid macro name '$name'"); |
1815
|
|
|
|
|
|
|
|
1816
|
|
|
|
|
|
|
# NOTE the value of {def} used to be unescaped, but I do not now |
1817
|
|
|
|
|
|
|
# know why, and the implementation of \U and friends is more natural |
1818
|
|
|
|
|
|
|
# with this stripped out. |
1819
|
|
|
|
|
|
|
$self->{macro}{$name} = |
1820
|
|
|
|
|
|
|
Astro::App::Satpass2::Macro::Command->new( |
1821
|
|
|
|
|
|
|
name => $name, |
1822
|
|
|
|
|
|
|
parent => $self, |
1823
|
|
|
|
|
|
|
completion => $opt->{completion}, |
1824
|
|
|
|
|
|
|
def => \@args, |
1825
|
|
|
|
|
|
|
generate => \&_macro_define_generator, |
1826
|
|
|
|
|
|
|
level1 => $self->{frame}[-1]{level1}, |
1827
|
|
|
|
|
|
|
warner => $self->{_warner}, |
1828
|
16
|
|
|
|
|
169
|
); |
1829
|
16
|
|
|
|
|
71
|
return $output; |
1830
|
20
|
|
|
20
|
|
8523
|
} |
|
20
|
|
|
|
|
69
|
|
|
20
|
|
|
|
|
91
|
|
1831
|
|
|
|
|
|
|
|
1832
|
|
|
|
|
|
|
sub _macro_define_generator { |
1833
|
9
|
|
|
9
|
|
29
|
my ( $self, @args ) = @_; # $self if Macro object |
1834
|
9
|
|
|
|
|
14
|
my $output; |
1835
|
9
|
|
|
|
|
20
|
foreach my $macro ( @args ) { |
1836
|
9
|
50
|
|
|
|
33
|
if ( my $comp = $self->completion() ) { |
1837
|
0
|
|
|
|
|
0
|
$output .= "macro define \\\n " . |
1838
|
|
|
|
|
|
|
"--completion '@$comp' \\\n " . |
1839
|
|
|
|
|
|
|
"$macro \\\n "; |
1840
|
|
|
|
|
|
|
} else { |
1841
|
9
|
|
|
|
|
32
|
$output .= "macro define $macro \\\n "; |
1842
|
|
|
|
|
|
|
} |
1843
|
9
|
|
|
|
|
27
|
$output .= join( " \\\n ", map { quoter( $_ ) } $self->def() ) . |
|
17
|
|
|
|
|
46
|
|
1844
|
|
|
|
|
|
|
"\n"; |
1845
|
|
|
|
|
|
|
} |
1846
|
9
|
|
|
|
|
33
|
return $output; |
1847
|
|
|
|
|
|
|
} |
1848
|
|
|
|
|
|
|
|
1849
|
|
|
|
|
|
|
sub _macro_sub_delete : Verb() Tweak( -completion _macro_list_complete ) { ## no critic (ProhibitUnusedPrivateSubroutines) |
1850
|
1
|
|
|
1
|
|
8
|
my ( $self, undef, @args ) = __arguments( @_ ); |
1851
|
1
|
|
|
|
|
6
|
my $output; |
1852
|
1
|
50
|
|
|
|
15
|
foreach my $name (@args ? @args : keys %{$self->{macro}}) { |
|
0
|
|
|
|
|
0
|
|
1853
|
1
|
|
|
|
|
13
|
delete $self->{macro}{$name}; |
1854
|
|
|
|
|
|
|
} |
1855
|
1
|
|
|
|
|
4
|
return $output; |
1856
|
20
|
|
|
20
|
|
8853
|
} |
|
20
|
|
|
|
|
51
|
|
|
20
|
|
|
|
|
103
|
|
1857
|
|
|
|
|
|
|
|
1858
|
|
|
|
|
|
|
sub _macro_sub_list : Verb() Tweak( -completion _macro_list_complete ) { ## no critic (ProhibitUnusedPrivateSubroutines) |
1859
|
9
|
|
|
9
|
|
37
|
my ( $self, undef, @args ) = __arguments( @_ ); |
1860
|
9
|
|
|
|
|
23
|
my $output; |
1861
|
9
|
100
|
|
|
|
37
|
foreach my $name (sort @args ? @args : keys %{$self->{macro}}) { |
|
1
|
|
|
|
|
10
|
|
1862
|
9
|
50
|
|
|
|
34
|
$self->{macro}{$name} |
1863
|
|
|
|
|
|
|
or next; |
1864
|
9
|
|
|
|
|
53
|
$output .= $self->{macro}{$name}->generator( $name ); |
1865
|
|
|
|
|
|
|
} |
1866
|
9
|
|
|
|
|
28
|
return $output; |
1867
|
20
|
|
|
20
|
|
6842
|
} |
|
20
|
|
|
|
|
45
|
|
|
20
|
|
|
|
|
90
|
|
1868
|
|
|
|
|
|
|
|
1869
|
|
|
|
|
|
|
sub _macro_sub_load : Verb( lib=s verbose! ) { ## no critic (ProhibitUnusedPrivateSubroutines) |
1870
|
0
|
|
|
0
|
|
0
|
my ( $self, $opt, $name, @args ) = __arguments( @_ ); |
1871
|
0
|
|
|
|
|
0
|
my $output; |
1872
|
0
|
0
|
|
|
|
0
|
defined $name |
1873
|
|
|
|
|
|
|
or $self->wail( 'Must provide name of macro to load' ); |
1874
|
|
|
|
|
|
|
my %marg = ( |
1875
|
|
|
|
|
|
|
name => $name, |
1876
|
|
|
|
|
|
|
parent => $self, |
1877
|
|
|
|
|
|
|
generate => \&_macro_load_generator, |
1878
|
|
|
|
|
|
|
warner => $self->{_warner}, |
1879
|
0
|
|
|
|
|
0
|
); |
1880
|
|
|
|
|
|
|
exists $opt->{lib} |
1881
|
0
|
0
|
|
|
|
0
|
and $marg{lib} = $opt->{lib}; |
1882
|
0
|
|
0
|
|
|
0
|
my $obj = $self->{_macro_load}{$name} ||= |
1883
|
|
|
|
|
|
|
Astro::App::Satpass2::Macro::Code->new( %marg ); |
1884
|
0
|
0
|
|
|
|
0
|
foreach my $mn ( @args ? @args : $obj->implements() ) { |
1885
|
|
|
|
|
|
|
$obj->implements( $mn, required => 1 ) |
1886
|
0
|
0
|
|
|
|
0
|
and $self->{macro}{$mn} = $obj; |
1887
|
|
|
|
|
|
|
} |
1888
|
0
|
0
|
|
|
|
0
|
if ( $opt->{verbose} ) { |
1889
|
0
|
|
|
|
|
0
|
( my $fn = "$name.pm" ) =~ s| :: |/|smxg; |
1890
|
0
|
|
|
|
|
0
|
$output .= "Macro $name\n loaded from $INC{$fn}\n"; |
1891
|
0
|
|
|
|
|
0
|
$output .= " implements:\n"; |
1892
|
0
|
|
|
|
|
0
|
$output .= " $_\n" for sort $obj->implements(); |
1893
|
|
|
|
|
|
|
} |
1894
|
0
|
0
|
|
|
|
0
|
$obj->implements( 'after_load', required => 0 ) |
1895
|
|
|
|
|
|
|
and $output .= $self->dispatch( after_load => $opt, $name, @args ); |
1896
|
0
|
|
|
|
|
0
|
return $output; |
1897
|
20
|
|
|
20
|
|
10433
|
} |
|
20
|
|
|
|
|
46
|
|
|
20
|
|
|
|
|
90
|
|
1898
|
|
|
|
|
|
|
|
1899
|
|
|
|
|
|
|
sub _macro_load_generator { |
1900
|
0
|
|
|
0
|
|
0
|
my ( $self, @args ) = @_; |
1901
|
0
|
|
|
|
|
0
|
my @preamble = qw{ macro load }; |
1902
|
0
|
0
|
|
|
|
0
|
if ( $self->has_lib() ) { |
1903
|
0
|
|
|
|
|
0
|
push @preamble, '-lib', $self->lib(); |
1904
|
0
|
0
|
|
|
|
0
|
$self->relative() |
1905
|
|
|
|
|
|
|
and push @preamble, '-relative'; |
1906
|
|
|
|
|
|
|
} |
1907
|
0
|
|
|
|
|
0
|
push @preamble, $self->name(); |
1908
|
0
|
|
|
|
|
0
|
my $output; |
1909
|
0
|
|
|
|
|
0
|
foreach my $macro ( @args ) { |
1910
|
0
|
|
|
|
|
0
|
$output .= quoter( @preamble, $macro ) . "\n"; |
1911
|
|
|
|
|
|
|
} |
1912
|
0
|
|
|
|
|
0
|
return $output; |
1913
|
|
|
|
|
|
|
} |
1914
|
|
|
|
|
|
|
|
1915
|
|
|
|
|
|
|
sub magnitude_table : Verb( name! reload! ) { |
1916
|
0
|
|
|
0
|
1
|
0
|
my ( undef, undef, @args ) = __arguments( @_ ); # Invocant, $opt unused |
1917
|
|
|
|
|
|
|
|
1918
|
0
|
0
|
|
|
|
0
|
@args or @args = qw{show}; |
1919
|
|
|
|
|
|
|
|
1920
|
0
|
|
0
|
|
|
0
|
my $verb = lc (shift (@args) || 'show'); |
1921
|
|
|
|
|
|
|
|
1922
|
0
|
|
|
|
|
0
|
my $output; |
1923
|
|
|
|
|
|
|
|
1924
|
0
|
0
|
0
|
|
|
0
|
if ( $verb eq 'show' || $verb eq 'list' ) { |
1925
|
|
|
|
|
|
|
|
1926
|
0
|
|
|
|
|
0
|
my %data = Astro::Coord::ECI::TLE->magnitude_table( 'show', @args ); |
1927
|
|
|
|
|
|
|
|
1928
|
0
|
|
|
|
|
0
|
foreach my $oid ( sort keys %data ) { |
1929
|
0
|
|
|
|
|
0
|
$output .= quoter( 'status', 'add', $oid, $data{$oid} ) |
1930
|
|
|
|
|
|
|
. "\n"; |
1931
|
|
|
|
|
|
|
} |
1932
|
|
|
|
|
|
|
|
1933
|
|
|
|
|
|
|
} else { |
1934
|
0
|
|
|
|
|
0
|
Astro::Coord::ECI::TLE->magnitude_table( $verb, @args ); |
1935
|
|
|
|
|
|
|
} |
1936
|
|
|
|
|
|
|
|
1937
|
0
|
|
|
|
|
0
|
return $output; |
1938
|
|
|
|
|
|
|
|
1939
|
20
|
|
|
20
|
|
10081
|
} |
|
20
|
|
|
|
|
48
|
|
|
20
|
|
|
|
|
90
|
|
1940
|
|
|
|
|
|
|
|
1941
|
|
|
|
|
|
|
# Attributes must all be on one line to process correctly under Perl |
1942
|
|
|
|
|
|
|
# 5.8.8. |
1943
|
|
|
|
|
|
|
sub pass : Verb( :compute __pass_options ) { |
1944
|
20
|
|
|
20
|
1
|
109
|
my ( $self, $opt, @args ) = __arguments( @_ ); |
1945
|
|
|
|
|
|
|
|
1946
|
|
|
|
|
|
|
$opt->{ephemeris} |
1947
|
20
|
100
|
|
|
|
126
|
and $opt->{almanac} = 1; |
1948
|
|
|
|
|
|
|
$opt->{almanac} |
1949
|
|
|
|
|
|
|
and not defined $opt->{ephemeris} |
1950
|
|
|
|
|
|
|
and $opt->{ephemeris} = { |
1951
|
|
|
|
|
|
|
pass_ics => 1, |
1952
|
20
|
100
|
100
|
|
|
112
|
}->{$opt->{_template}}; |
1953
|
|
|
|
|
|
|
|
1954
|
20
|
|
|
|
|
131
|
$self->_apply_boolean_default( |
1955
|
|
|
|
|
|
|
$opt, 0, qw{ horizon illumination transit appulse } ); |
1956
|
20
|
|
|
|
|
102
|
$self->_apply_boolean_default( $opt, 0, qw{ am pm } ); |
1957
|
20
|
50
|
66
|
|
|
196
|
$opt->{am} or $opt->{pm} or $opt->{am} = $opt->{pm} = 1; |
1958
|
20
|
|
|
|
|
151
|
my $pass_start = $self->__parse_time ( |
1959
|
|
|
|
|
|
|
shift @args, $self->_get_day_noon()); |
1960
|
20
|
|
100
|
|
|
126
|
my $pass_end = $self->__parse_time (shift @args || '+7'); |
1961
|
20
|
50
|
|
|
|
87
|
$pass_start >= $pass_end |
1962
|
|
|
|
|
|
|
and $self->wail( 'End time must be after start time' ); |
1963
|
|
|
|
|
|
|
|
1964
|
20
|
|
|
|
|
117
|
my $sta = $self->station(); |
1965
|
|
|
|
|
|
|
my @bodies = $self->__choose( $opt->{choose}, $self->{bodies} ) |
1966
|
20
|
50
|
|
|
|
7933
|
or $self->wail( 'No bodies selected' ); |
1967
|
20
|
|
50
|
|
|
131
|
my $pass_step = shift @args || 60; |
1968
|
|
|
|
|
|
|
|
1969
|
|
|
|
|
|
|
# Decide which model to use. |
1970
|
|
|
|
|
|
|
|
1971
|
20
|
|
|
|
|
73
|
my $model = $self->{model}; |
1972
|
|
|
|
|
|
|
|
1973
|
|
|
|
|
|
|
# Set the station for the objects in the sky. |
1974
|
|
|
|
|
|
|
|
1975
|
20
|
|
|
|
|
40
|
foreach my $body ( @{ $self->{sky} } ) { |
|
20
|
|
|
|
|
91
|
|
1976
|
41
|
|
|
|
|
2092
|
$body->set( station => $sta ); |
1977
|
|
|
|
|
|
|
} |
1978
|
|
|
|
|
|
|
|
1979
|
|
|
|
|
|
|
# Pick up horizon and appulse distance. |
1980
|
|
|
|
|
|
|
|
1981
|
20
|
|
|
|
|
1263
|
my $horizon = deg2rad ($self->{horizon}); |
1982
|
20
|
|
|
|
|
136
|
my $appulse = deg2rad ($self->{appulse}); |
1983
|
20
|
|
|
|
|
113
|
my $pass_threshold = deg2rad( $self->{pass_threshold} ); |
1984
|
|
|
|
|
|
|
|
1985
|
|
|
|
|
|
|
# In order that the interface not be completely rude, the interface |
1986
|
|
|
|
|
|
|
# allows -brightest to specify that you want the 'brightest' event. |
1987
|
|
|
|
|
|
|
# But this is controlled by the pass_variant attribute. So if |
1988
|
|
|
|
|
|
|
# -brightest appears, the pass_variant from it; otherwise we default |
1989
|
|
|
|
|
|
|
# -brightest from the pass_variant attribute. We localize the |
1990
|
|
|
|
|
|
|
# pass_variant attribute before modifying it, since the -brightest |
1991
|
|
|
|
|
|
|
# option is to hold for this call only. We modify it (rather than |
1992
|
|
|
|
|
|
|
# just passing a local copy to the bodies) because |
1993
|
|
|
|
|
|
|
# Formatter::Template needs to know what it is, and modifying this |
1994
|
|
|
|
|
|
|
# object is the obvious way to pass the information. |
1995
|
20
|
|
|
|
|
127
|
local $self->{pass_variant} = $self->{pass_variant}; |
1996
|
20
|
50
|
|
|
|
76
|
if ( $opt->{brightest} ) { |
|
|
50
|
|
|
|
|
|
1997
|
0
|
|
|
|
|
0
|
$self->{pass_variant} |= PASS_VARIANT_BRIGHTEST; |
1998
|
|
|
|
|
|
|
} elsif ( exists $opt->{brightest} ) { |
1999
|
0
|
|
|
|
|
0
|
$self->{pass_variant} &= ~ PASS_VARIANT_BRIGHTEST; |
2000
|
|
|
|
|
|
|
} else { |
2001
|
20
|
|
|
|
|
83
|
$opt->{brightest} = $self->{pass_variant} & PASS_VARIANT_BRIGHTEST; |
2002
|
|
|
|
|
|
|
} |
2003
|
20
|
|
|
|
|
53
|
my $pass_variant = $self->{pass_variant}; |
2004
|
|
|
|
|
|
|
|
2005
|
|
|
|
|
|
|
# Foreach body to be modelled |
2006
|
|
|
|
|
|
|
|
2007
|
20
|
|
|
|
|
44
|
my @accumulate; # For chronological output. |
2008
|
20
|
|
|
|
|
96
|
foreach my $tle ( $self->_aggregate( \@bodies ) ) { |
2009
|
|
|
|
|
|
|
|
2010
|
|
|
|
|
|
|
{ |
2011
|
39
|
50
|
|
|
|
2569
|
my $mdl = $tle->get('inertial') ? $model : |
|
39
|
|
|
|
|
125
|
|
2012
|
|
|
|
|
|
|
$tle->get('model'); |
2013
|
|
|
|
|
|
|
$tle->set ( |
2014
|
|
|
|
|
|
|
appulse => $appulse, |
2015
|
|
|
|
|
|
|
backdate => $self->{backdate}, |
2016
|
|
|
|
|
|
|
debug => $self->{debug}, |
2017
|
|
|
|
|
|
|
edge_of_earths_shadow => $self->{edge_of_earths_shadow}, |
2018
|
|
|
|
|
|
|
geometric => $self->{geometric}, |
2019
|
|
|
|
|
|
|
horizon => $horizon, |
2020
|
|
|
|
|
|
|
interval => ( $self->{verbose} ? $pass_step : 0 ), |
2021
|
|
|
|
|
|
|
model => $mdl, |
2022
|
|
|
|
|
|
|
pass_threshold => $pass_threshold, |
2023
|
|
|
|
|
|
|
pass_variant => $pass_variant, |
2024
|
|
|
|
|
|
|
station => $sta, |
2025
|
|
|
|
|
|
|
twilight => $self->{_twilight}, |
2026
|
|
|
|
|
|
|
visible => $self->{visible}, |
2027
|
39
|
50
|
|
|
|
1321
|
); |
2028
|
|
|
|
|
|
|
} |
2029
|
|
|
|
|
|
|
|
2030
|
|
|
|
|
|
|
eval { |
2031
|
|
|
|
|
|
|
push @accumulate, $self->_pass_select_event( $opt, $tle->pass ( |
2032
|
39
|
|
|
|
|
286
|
$pass_start, $pass_end, $self->{sky} ) ); |
2033
|
39
|
|
|
|
|
242
|
1; |
2034
|
39
|
50
|
|
|
|
13621
|
} or do { |
2035
|
0
|
0
|
|
|
|
0
|
$@ =~ m/ \Q$interrupted\E /smxo and $self->wail($@); |
2036
|
0
|
0
|
|
|
|
0
|
$opt->{quiet} or $self->whinge($@); |
2037
|
|
|
|
|
|
|
}; |
2038
|
|
|
|
|
|
|
} |
2039
|
|
|
|
|
|
|
|
2040
|
20
|
|
|
|
|
120
|
@accumulate = $self->__pass_filter_am_pm( $opt, @accumulate ); |
2041
|
|
|
|
|
|
|
|
2042
|
|
|
|
|
|
|
$opt->{chronological} |
2043
|
20
|
100
|
|
|
|
93
|
and @accumulate = sort { $a->{time} <=> $b->{time} } |
|
0
|
|
|
|
|
0
|
|
2044
|
|
|
|
|
|
|
@accumulate; |
2045
|
|
|
|
|
|
|
|
2046
|
|
|
|
|
|
|
# Record number of events found. |
2047
|
|
|
|
|
|
|
# NOTE that in this case an event is an entire pass. |
2048
|
|
|
|
|
|
|
|
2049
|
20
|
|
|
|
|
97
|
$self->{events} += @accumulate; |
2050
|
|
|
|
|
|
|
|
2051
|
20
|
100
|
|
|
|
90
|
if ( $opt->{almanac} ) { |
2052
|
4
|
|
|
|
|
14
|
my %almanac; |
2053
|
4
|
|
|
|
|
15
|
foreach my $pass ( @accumulate ) { |
2054
|
6
|
|
|
|
|
40
|
my $illum = $pass->{body}->get( 'illum' ); |
2055
|
6
|
|
|
|
|
114
|
my $noon = $self->_get_day_noon( $pass->{time} ); |
2056
|
6
|
|
33
|
|
|
521
|
$almanac{$noon}{$illum} ||= do { |
2057
|
6
|
|
|
|
|
19
|
my @day; |
2058
|
|
|
|
|
|
|
|
2059
|
|
|
|
|
|
|
my @events = grep { { |
2060
|
|
|
|
|
|
|
horizon => 1, |
2061
|
|
|
|
|
|
|
twilight => 1, |
2062
|
|
|
|
|
|
|
}->{$_->{almanac}{event}} |
2063
|
36
|
|
|
|
|
1043852
|
} $illum->almanac_hash( |
2064
|
6
|
|
|
|
|
55
|
$self->_get_day_midnight( $pass->{time} ) ); |
2065
|
|
|
|
|
|
|
|
2066
|
6
|
|
|
|
|
61
|
_almanac_localize( @events ); |
2067
|
|
|
|
|
|
|
|
2068
|
6
|
|
|
|
|
20
|
foreach my $evt ( @events ) { |
2069
|
24
|
|
|
|
|
70
|
$evt->{event} = 'almanac'; |
2070
|
24
|
100
|
|
|
|
70
|
my $pm = $evt->{time} >= $noon ? 1 : 0; |
2071
|
24
|
|
|
|
|
40
|
push @{ $day[$pm] }, $evt; |
|
24
|
|
|
|
|
59
|
|
2072
|
|
|
|
|
|
|
} |
2073
|
|
|
|
|
|
|
|
2074
|
6
|
|
|
|
|
55
|
\@day; |
2075
|
|
|
|
|
|
|
}; |
2076
|
|
|
|
|
|
|
|
2077
|
6
|
50
|
|
|
|
34
|
$pass->{_pm} = my $pm = $pass->{time} >= $noon ? 1 : 0; |
2078
|
|
|
|
|
|
|
# TODO this way ALL passes get the almanac events. Is this |
2079
|
|
|
|
|
|
|
# what I want? It varies. For --ics it is. For --events it |
2080
|
|
|
|
|
|
|
# is not. For neither it's probably not. |
2081
|
6
|
100
|
|
|
|
39
|
if ( $opt->{ephemeris} ) { |
2082
|
3
|
|
|
|
|
21
|
@{ $pass->{events} } = sort { $a->{time} <=> $b->{time} |
2083
|
3
|
|
|
|
|
9
|
} @{ $pass->{events} }, @{ $almanac{$noon}{$illum}[$pm] }; |
|
26
|
|
|
|
|
58
|
|
|
3
|
|
|
|
|
10
|
|
|
3
|
|
|
|
|
29
|
|
2084
|
|
|
|
|
|
|
} |
2085
|
|
|
|
|
|
|
} |
2086
|
|
|
|
|
|
|
|
2087
|
4
|
100
|
|
|
|
47
|
unless( $opt->{ephemeris} ) { |
2088
|
2
|
|
|
|
|
9
|
foreach my $pass ( @accumulate ) { |
2089
|
|
|
|
|
|
|
$pass->{_pm} |
2090
|
3
|
50
|
|
|
|
16
|
or next; |
2091
|
0
|
|
|
|
|
0
|
my $illum = $pass->{body}->get( 'illum' ); |
2092
|
0
|
|
|
|
|
0
|
my $noon = $self->_get_day_noon( $pass->{time} ); |
2093
|
0
|
0
|
|
|
|
0
|
$almanac{$noon}{$illum}[1] |
2094
|
|
|
|
|
|
|
or next; |
2095
|
0
|
|
|
|
|
0
|
@{ $pass->{events} } = sort { $a->{time} <=> $b->{time} } |
|
0
|
|
|
|
|
0
|
|
2096
|
0
|
|
|
|
|
0
|
@{ $pass->{events} }, |
2097
|
0
|
|
|
|
|
0
|
@{ $almanac{$noon}{$illum}[1] }; |
|
0
|
|
|
|
|
0
|
|
2098
|
0
|
|
|
|
|
0
|
$almanac{$noon}{$illum}[1] = undef; |
2099
|
|
|
|
|
|
|
} |
2100
|
2
|
|
|
|
|
7
|
foreach my $pass ( reverse @accumulate ) { |
2101
|
|
|
|
|
|
|
$pass->{_pm} |
2102
|
3
|
50
|
|
|
|
16
|
and next; |
2103
|
3
|
|
|
|
|
21
|
my $illum = $pass->{body}->get( 'illum' ); |
2104
|
3
|
|
|
|
|
51
|
my $noon = $self->_get_day_noon( $pass->{time} ); |
2105
|
3
|
50
|
|
|
|
186
|
$almanac{$noon}{$illum}[0] |
2106
|
|
|
|
|
|
|
or next; |
2107
|
3
|
|
|
|
|
18
|
@{ $pass->{events} } = sort { $a->{time} <=> $b->{time} } |
|
26
|
|
|
|
|
52
|
|
2108
|
3
|
|
|
|
|
10
|
@{ $pass->{events} }, |
2109
|
3
|
|
|
|
|
10
|
@{ $almanac{$noon}{$illum}[0] }; |
|
3
|
|
|
|
|
16
|
|
2110
|
3
|
|
|
|
|
46
|
$almanac{$noon}{$illum}[0] = undef; |
2111
|
|
|
|
|
|
|
} |
2112
|
|
|
|
|
|
|
} |
2113
|
|
|
|
|
|
|
} |
2114
|
|
|
|
|
|
|
|
2115
|
|
|
|
|
|
|
return $self->__format_data( |
2116
|
20
|
|
|
|
|
126
|
$opt->{_template} => \@accumulate, $opt ); |
2117
|
|
|
|
|
|
|
|
2118
|
20
|
|
|
20
|
|
25817
|
} |
|
20
|
|
|
|
|
79
|
|
|
20
|
|
|
|
|
98
|
|
2119
|
|
|
|
|
|
|
|
2120
|
|
|
|
|
|
|
sub __pass_filter_am_pm { |
2121
|
20
|
|
|
20
|
|
77
|
my ( $self, $opt, @accumulate ) = @_; |
2122
|
20
|
|
50
|
|
|
92
|
$opt ||= {}; |
2123
|
|
|
|
|
|
|
$opt->{am} xor $opt->{pm} |
2124
|
20
|
100
|
75
|
|
|
207
|
or return @accumulate; |
2125
|
|
|
|
|
|
|
return ( |
2126
|
6
|
|
|
|
|
11
|
map { $_->[0] } |
2127
|
12
|
|
50
|
|
|
155
|
grep { $opt->{am} xor $_->[1] } |
2128
|
2
|
|
|
|
|
7
|
map { [ |
2129
|
|
|
|
|
|
|
$_, |
2130
|
|
|
|
|
|
|
$_->{time} >= $self->_get_day_noon( $_->{time} ) |
2131
|
12
|
|
|
|
|
374
|
] } @accumulate |
2132
|
|
|
|
|
|
|
); |
2133
|
|
|
|
|
|
|
} |
2134
|
|
|
|
|
|
|
|
2135
|
|
|
|
|
|
|
sub __pass_options { |
2136
|
20
|
|
|
20
|
|
74
|
my ( $self, $opt ) = @_; |
2137
|
|
|
|
|
|
|
return [ |
2138
|
20
|
|
|
|
|
135
|
qw{ |
2139
|
|
|
|
|
|
|
almanac! am! appulse! brightest|magnitude! choose=s@ |
2140
|
|
|
|
|
|
|
chronological! ephemeris! dump! horizon|rise|set! |
2141
|
|
|
|
|
|
|
illumination! pm! |
2142
|
|
|
|
|
|
|
quiet! transit|maximum|culmination! |
2143
|
|
|
|
|
|
|
}, |
2144
|
|
|
|
|
|
|
$self->_templates_to_options( pass => $opt ), |
2145
|
|
|
|
|
|
|
]; |
2146
|
|
|
|
|
|
|
} |
2147
|
|
|
|
|
|
|
|
2148
|
|
|
|
|
|
|
{ |
2149
|
|
|
|
|
|
|
my @selector; |
2150
|
|
|
|
|
|
|
$selector[ PASS_EVENT_SHADOWED ] = 'illumination'; |
2151
|
|
|
|
|
|
|
$selector[ PASS_EVENT_LIT ] = 'illumination'; |
2152
|
|
|
|
|
|
|
$selector[ PASS_EVENT_DAY ] = 'illumination'; |
2153
|
|
|
|
|
|
|
$selector[ PASS_EVENT_RISE ] = 'horizon'; |
2154
|
|
|
|
|
|
|
$selector[ PASS_EVENT_MAX ] = 'transit'; |
2155
|
|
|
|
|
|
|
$selector[ PASS_EVENT_SET ] = 'horizon'; |
2156
|
|
|
|
|
|
|
$selector[ PASS_EVENT_APPULSE ] = 'appulse'; |
2157
|
|
|
|
|
|
|
$selector[ PASS_EVENT_START ] = 'horizon'; |
2158
|
|
|
|
|
|
|
$selector[ PASS_EVENT_END ] = 'horizon'; |
2159
|
|
|
|
|
|
|
$selector[ PASS_EVENT_BRIGHTEST ] = 'brightest'; |
2160
|
|
|
|
|
|
|
|
2161
|
|
|
|
|
|
|
# Remove from the pass data any events that are not wanted. The |
2162
|
|
|
|
|
|
|
# arguments are $self, the $opt hash reference that (among other |
2163
|
|
|
|
|
|
|
# things) specifies the desired events, and the passes, each pass |
2164
|
|
|
|
|
|
|
# being an argument. The modified passes are returned. |
2165
|
|
|
|
|
|
|
sub _pass_select_event { |
2166
|
39
|
|
|
39
|
|
52399184
|
my ( undef, $opt, @passes ) = @_; # Invocant unused |
2167
|
39
|
|
|
|
|
86
|
my @rslt; |
2168
|
39
|
|
|
|
|
148
|
foreach my $pass ( @passes ) { |
2169
|
38
|
|
|
|
|
236
|
@{ $pass->{events} } = grep { |
2170
|
|
|
|
|
|
|
_pass_select_event_code( $opt, $_->{event} ) |
2171
|
38
|
50
|
|
|
|
78
|
} @{ $pass->{events} } |
|
136
|
|
|
|
|
353
|
|
|
38
|
|
|
|
|
143
|
|
2172
|
|
|
|
|
|
|
and push @rslt, $pass; |
2173
|
|
|
|
|
|
|
} |
2174
|
|
|
|
|
|
|
return @rslt |
2175
|
39
|
|
|
|
|
131
|
} |
2176
|
|
|
|
|
|
|
|
2177
|
|
|
|
|
|
|
# Determine whether an event is to be reported for the pass. The |
2178
|
|
|
|
|
|
|
# arguments are the $opt hash reference and the event code or name. |
2179
|
|
|
|
|
|
|
# Anything that is not a dualvar and not an integer is accepted, on |
2180
|
|
|
|
|
|
|
# the presumption that it is an ad-hoc event provided by some |
2181
|
|
|
|
|
|
|
# subclass. The null event is always accepted on the presumption |
2182
|
|
|
|
|
|
|
# that if the user did not want it he or she would not have asked |
2183
|
|
|
|
|
|
|
# for it. Anything that is left is accepted or rejected based on the |
2184
|
|
|
|
|
|
|
# option hash and the @selector array (defined above). |
2185
|
|
|
|
|
|
|
sub _pass_select_event_code { |
2186
|
136
|
|
|
136
|
|
286
|
my ( $opt, $event ) = @_; |
2187
|
136
|
50
|
33
|
|
|
378
|
isdual( $event ) |
2188
|
|
|
|
|
|
|
or $event !~ m/ \D /smx |
2189
|
|
|
|
|
|
|
or return 1; |
2190
|
136
|
50
|
|
|
|
278
|
$event == PASS_EVENT_NONE |
2191
|
|
|
|
|
|
|
and return 1; |
2192
|
136
|
|
66
|
|
|
706
|
return defined $selector[ $event ] && $opt->{ $selector[ $event ] }; |
2193
|
|
|
|
|
|
|
} |
2194
|
|
|
|
|
|
|
} |
2195
|
|
|
|
|
|
|
|
2196
|
|
|
|
|
|
|
sub perl : Tokenize( -noexpand_tilde ) : Verb( eval! setup! ) { |
2197
|
2
|
|
|
2
|
1
|
22
|
my ( $self, $opt, $file, @args ) = __arguments( @_ ); |
2198
|
2
|
50
|
|
|
|
16
|
defined $file |
2199
|
|
|
|
|
|
|
or $self->wail( 'At least one argument is required' ); |
2200
|
|
|
|
|
|
|
$opt->{setup} |
2201
|
2
|
50
|
0
|
|
|
14
|
and push @{ $self->{_perl} ||= [] }, [ $opt, $file, @args ]; |
|
0
|
|
|
|
|
0
|
|
2202
|
2
|
|
|
|
|
17
|
local @ARGV = ( $self, map { $self->expand_tilde( $_ ) } @args ); |
|
0
|
|
|
|
|
0
|
|
2203
|
|
|
|
|
|
|
$opt->{eval} |
2204
|
2
|
100
|
|
|
|
35
|
or local $0 = $self->expand_tilde( $file ); |
2205
|
|
|
|
|
|
|
|
2206
|
|
|
|
|
|
|
my $data = $opt->{eval} ? |
2207
|
2
|
100
|
|
|
|
39
|
$file : |
2208
|
|
|
|
|
|
|
$self->_file_reader( $file, { glob => 1 } ); |
2209
|
2
|
|
|
|
|
213
|
my $rslt = eval $data; ## no critic (BuiltinFunctions::ProhibitStringyEval) |
2210
|
2
|
100
|
|
|
|
39
|
$@ |
2211
|
|
|
|
|
|
|
and $self->wail( "Failed to eval '$file': $@" ); |
2212
|
1
|
50
|
|
|
|
12
|
instance( $rslt, 'Astro::App::Satpass2' ) |
2213
|
|
|
|
|
|
|
or return $rslt; |
2214
|
0
|
|
|
|
|
0
|
return; |
2215
|
20
|
|
|
20
|
|
17162
|
} |
|
20
|
|
|
|
|
71
|
|
|
20
|
|
|
|
|
93
|
|
2216
|
|
|
|
|
|
|
|
2217
|
|
|
|
|
|
|
sub phase : Verb( choose=s@ ) { |
2218
|
1
|
|
|
1
|
1
|
9
|
my ( $self, $opt, @args ) = __arguments( @_ ); |
2219
|
|
|
|
|
|
|
|
2220
|
1
|
|
|
|
|
12
|
my $time = $self->__parse_time (shift @args, time ); |
2221
|
|
|
|
|
|
|
|
2222
|
|
|
|
|
|
|
my @sky = $self->__choose( $opt->{choose}, $self->{sky} ) |
2223
|
1
|
50
|
|
|
|
8
|
or $self->wail( 'No bodies selected' ); |
2224
|
|
|
|
|
|
|
return $self->__format_data( |
2225
|
|
|
|
|
|
|
phase => [ |
2226
|
1
|
|
|
|
|
5
|
map { { body => $_->universal( $time ), time => $time } } |
2227
|
1
|
|
|
|
|
4
|
grep { $_->can( 'phase' ) } |
|
2
|
|
|
|
|
18
|
|
2228
|
|
|
|
|
|
|
@sky |
2229
|
|
|
|
|
|
|
], $opt ); |
2230
|
20
|
|
|
20
|
|
7328
|
} |
|
20
|
|
|
|
|
55
|
|
|
20
|
|
|
|
|
104
|
|
2231
|
|
|
|
|
|
|
|
2232
|
|
|
|
|
|
|
sub position : Verb( choose=s@ questionable|spare! quiet! ) { |
2233
|
4
|
|
|
4
|
1
|
28090
|
my ( $self, $opt, $time ) = __arguments( @_ ); |
2234
|
|
|
|
|
|
|
|
2235
|
4
|
50
|
|
|
|
29
|
if ( defined $time ) { |
2236
|
4
|
|
|
|
|
13
|
$time = $self->__parse_time($time); |
2237
|
|
|
|
|
|
|
} else { |
2238
|
0
|
|
|
|
|
0
|
$time = time; |
2239
|
|
|
|
|
|
|
} |
2240
|
|
|
|
|
|
|
|
2241
|
|
|
|
|
|
|
# Define the observing station. |
2242
|
|
|
|
|
|
|
|
2243
|
4
|
|
|
|
|
21
|
my $sta = $self->station(); |
2244
|
4
|
|
|
|
|
1619
|
$sta->universal( $time ); |
2245
|
|
|
|
|
|
|
|
2246
|
|
|
|
|
|
|
my @list = $self->__choose( { bodies => 1, sky => 1 }, |
2247
|
4
|
|
|
|
|
208
|
$opt->{choose} ); |
2248
|
|
|
|
|
|
|
|
2249
|
4
|
|
|
|
|
22
|
my @good; |
2250
|
4
|
|
|
|
|
17
|
my $horizon = deg2rad ($self->{horizon}); |
2251
|
4
|
|
|
|
|
37
|
foreach my $body (@list) { |
2252
|
13
|
100
|
|
|
|
59
|
if ( $body->represents( 'Astro::Coord::ECI::TLE' ) ) { |
2253
|
|
|
|
|
|
|
$body->set ( |
2254
|
|
|
|
|
|
|
backdate => $self->{backdate}, |
2255
|
|
|
|
|
|
|
debug => $self->{debug}, |
2256
|
|
|
|
|
|
|
edge_of_earths_shadow => $self->{edge_of_earths_shadow}, |
2257
|
|
|
|
|
|
|
geometric => $self->{geometric}, |
2258
|
|
|
|
|
|
|
horizon => $horizon, |
2259
|
|
|
|
|
|
|
station => $sta, |
2260
|
|
|
|
|
|
|
twilight => $self->{_twilight}, |
2261
|
4
|
|
|
|
|
151
|
); |
2262
|
|
|
|
|
|
|
$body->get('inertial') |
2263
|
4
|
50
|
|
|
|
915
|
and $body->set( model => $self->{model} ); |
2264
|
|
|
|
|
|
|
} |
2265
|
|
|
|
|
|
|
eval { |
2266
|
13
|
|
|
|
|
46
|
$body->universal ($time); |
2267
|
10
|
|
|
|
|
3665
|
push @good, $body; |
2268
|
10
|
|
|
|
|
34
|
1; |
2269
|
13
|
100
|
|
|
|
457
|
} or do { |
2270
|
3
|
50
|
|
|
|
2108
|
$@ =~ m/ \Q$interrupted\E /smxo and $self->wail($@); |
2271
|
3
|
50
|
|
|
|
19
|
$opt->{quiet} or $self->whinge($@); |
2272
|
|
|
|
|
|
|
}; |
2273
|
|
|
|
|
|
|
} |
2274
|
|
|
|
|
|
|
|
2275
|
|
|
|
|
|
|
return $self->__format_data( |
2276
|
|
|
|
|
|
|
position => { |
2277
|
|
|
|
|
|
|
bodies => \@good, |
2278
|
|
|
|
|
|
|
questionable => $opt->{questionable}, |
2279
|
|
|
|
|
|
|
station => $self->station()->universal( |
2280
|
|
|
|
|
|
|
$time ), |
2281
|
|
|
|
|
|
|
time => $time, |
2282
|
|
|
|
|
|
|
twilight => $self->{_twilight}, |
2283
|
4
|
|
|
|
|
48
|
}, $opt ); |
2284
|
20
|
|
|
20
|
|
10881
|
} |
|
20
|
|
|
|
|
56
|
|
|
20
|
|
|
|
|
134
|
|
2285
|
|
|
|
|
|
|
|
2286
|
|
|
|
|
|
|
sub pwd : Verb() { |
2287
|
1
|
|
|
1
|
1
|
3836
|
return Cwd::cwd() . "\n"; |
2288
|
20
|
|
|
20
|
|
4366
|
} |
|
20
|
|
|
|
|
54
|
|
|
20
|
|
|
|
|
81
|
|
2289
|
|
|
|
|
|
|
|
2290
|
|
|
|
|
|
|
{ |
2291
|
|
|
|
|
|
|
my @quarter_name = map { "q$_" } 0 .. 3; |
2292
|
|
|
|
|
|
|
|
2293
|
|
|
|
|
|
|
sub quarters : Verb( choose=s@ dump! q0|new|spring! q1|first|summer! q2|full|fall q3|last|winter ) { |
2294
|
1
|
|
|
1
|
1
|
36
|
my ( $self, $opt, @args ) = __arguments( @_ ); |
2295
|
|
|
|
|
|
|
|
2296
|
1
|
|
|
|
|
26
|
my $start = $self->__parse_time ( |
2297
|
|
|
|
|
|
|
$args[0], $self->_get_day_midnight() ); |
2298
|
1
|
|
50
|
|
|
32
|
my $end = $self->__parse_time ($args[1] || '+30'); |
2299
|
|
|
|
|
|
|
|
2300
|
1
|
|
|
|
|
11
|
$self->_apply_boolean_default( $opt, 0, map { "q$_" } 0 .. 3 ); |
|
4
|
|
|
|
|
36
|
|
2301
|
|
|
|
|
|
|
|
2302
|
|
|
|
|
|
|
my @sky = $self->__choose( $opt->{choose}, $self->{sky} ) |
2303
|
1
|
50
|
|
|
|
27
|
or $self->wail( 'No bodies selected' ); |
2304
|
|
|
|
|
|
|
|
2305
|
1
|
|
|
|
|
4
|
my @almanac; |
2306
|
|
|
|
|
|
|
|
2307
|
|
|
|
|
|
|
# Iterate over any background objects, accumulating all |
2308
|
|
|
|
|
|
|
# quarter-phases of each until we get one after the end time. We |
2309
|
|
|
|
|
|
|
# silently ignore bodies that do not support the next_quarter() |
2310
|
|
|
|
|
|
|
# method. |
2311
|
|
|
|
|
|
|
|
2312
|
1
|
|
|
|
|
12
|
foreach my $body ( @sky ) { |
2313
|
2
|
50
|
|
|
|
37
|
next unless $body->can ('next_quarter_hash'); |
2314
|
2
|
|
|
|
|
26
|
$body->universal ($start); |
2315
|
|
|
|
|
|
|
|
2316
|
2
|
|
|
|
|
2351
|
while (1) { |
2317
|
7
|
|
|
|
|
37
|
my $hash = $body->next_quarter_hash(); |
2318
|
7
|
100
|
|
|
|
201337
|
$hash->{time} > $end and last; |
2319
|
5
|
50
|
|
|
|
40
|
$opt->{$quarter_name[$hash->{almanac}{detail}]} |
2320
|
|
|
|
|
|
|
or next; |
2321
|
5
|
|
|
|
|
17
|
push @almanac, $hash; |
2322
|
|
|
|
|
|
|
} |
2323
|
|
|
|
|
|
|
} |
2324
|
|
|
|
|
|
|
|
2325
|
|
|
|
|
|
|
# Localize the event descriptions if appropriate. |
2326
|
|
|
|
|
|
|
|
2327
|
1
|
|
|
|
|
7
|
foreach my $event ( @almanac ) { |
2328
|
|
|
|
|
|
|
$event->{almanac}{description} = __localize( |
2329
|
|
|
|
|
|
|
text => [ almanac => $event->{body}->get( 'name' ), |
2330
|
|
|
|
|
|
|
$event->{almanac}{event}, $event->{almanac}{detail} |
2331
|
|
|
|
|
|
|
], |
2332
|
|
|
|
|
|
|
default => $event->{almanac}{description}, |
2333
|
|
|
|
|
|
|
argument => $event->{body}, |
2334
|
5
|
|
|
|
|
33
|
); |
2335
|
|
|
|
|
|
|
} |
2336
|
|
|
|
|
|
|
|
2337
|
|
|
|
|
|
|
# Record number of events found |
2338
|
|
|
|
|
|
|
|
2339
|
1
|
|
|
|
|
22
|
$self->{events} += @almanac; |
2340
|
|
|
|
|
|
|
|
2341
|
|
|
|
|
|
|
# Sort and display the quarter-phase information. |
2342
|
|
|
|
|
|
|
|
2343
|
|
|
|
|
|
|
return $self->__format_data( |
2344
|
|
|
|
|
|
|
almanac => [ |
2345
|
1
|
|
|
|
|
39
|
sort { $a->{time} <=> $b->{time} } |
|
9
|
|
|
|
|
51
|
|
2346
|
|
|
|
|
|
|
@almanac |
2347
|
|
|
|
|
|
|
], $opt ); |
2348
|
|
|
|
|
|
|
|
2349
|
20
|
|
|
20
|
|
11503
|
} |
|
20
|
|
|
|
|
44
|
|
|
20
|
|
|
|
|
117
|
|
2350
|
|
|
|
|
|
|
} |
2351
|
|
|
|
|
|
|
|
2352
|
|
|
|
|
|
|
{ |
2353
|
|
|
|
|
|
|
my $go; |
2354
|
|
|
|
|
|
|
|
2355
|
|
|
|
|
|
|
sub run { |
2356
|
0
|
|
|
0
|
1
|
0
|
my ( $self, @args ) = @_; |
2357
|
|
|
|
|
|
|
|
2358
|
|
|
|
|
|
|
# We can be called statically. If we are, instantiate. |
2359
|
0
|
0
|
|
|
|
0
|
ref $self or $self = $self->new(warning => 1); |
2360
|
|
|
|
|
|
|
|
2361
|
|
|
|
|
|
|
# Put all the I/O into UTF-8 mode. |
2362
|
0
|
|
|
|
|
0
|
binmode STDIN, ':encoding(UTF-8)'; |
2363
|
0
|
|
|
|
|
0
|
binmode STDOUT, DEFAULT_STDOUT_LAYERS; |
2364
|
0
|
|
|
|
|
0
|
binmode STDERR, ':encoding(UTF-8)'; |
2365
|
|
|
|
|
|
|
|
2366
|
|
|
|
|
|
|
# If the undocumented first option is a code reference, use it to |
2367
|
|
|
|
|
|
|
# get input. |
2368
|
0
|
|
|
|
|
0
|
my $in; |
2369
|
0
|
0
|
|
|
|
0
|
CODE_REF eq ref $args[0] |
2370
|
|
|
|
|
|
|
and $in = shift @args; |
2371
|
|
|
|
|
|
|
|
2372
|
|
|
|
|
|
|
# Parse the command options. -level1 is undocumented. |
2373
|
0
|
|
|
|
|
0
|
my %opt; |
2374
|
0
|
|
0
|
|
|
0
|
$go ||= Getopt::Long::Parser->new(); |
2375
|
0
|
0
|
|
|
|
0
|
$go->getoptionsfromarray( |
2376
|
|
|
|
|
|
|
\@args, |
2377
|
|
|
|
|
|
|
\%opt, |
2378
|
|
|
|
|
|
|
qw{ |
2379
|
|
|
|
|
|
|
echo! filter! gmt! help initialization_file|initfile=s |
2380
|
|
|
|
|
|
|
level1! version |
2381
|
|
|
|
|
|
|
}, |
2382
|
|
|
|
|
|
|
) |
2383
|
|
|
|
|
|
|
or $self->wail( 'See the help method for valid options' ); |
2384
|
|
|
|
|
|
|
|
2385
|
|
|
|
|
|
|
# If -version, do it and return. |
2386
|
0
|
0
|
|
|
|
0
|
if ( $opt{version} ) { |
2387
|
0
|
|
|
|
|
0
|
print $self->version(); |
2388
|
0
|
|
|
|
|
0
|
return; |
2389
|
|
|
|
|
|
|
} |
2390
|
|
|
|
|
|
|
|
2391
|
|
|
|
|
|
|
# If -help, do it and return. |
2392
|
0
|
0
|
|
|
|
0
|
if ( $opt{help} ) { |
2393
|
0
|
|
|
|
|
0
|
$self->help(); |
2394
|
0
|
|
|
|
|
0
|
return; |
2395
|
|
|
|
|
|
|
} |
2396
|
|
|
|
|
|
|
|
2397
|
|
|
|
|
|
|
# Get an input routine if we do not already have one. |
2398
|
0
|
|
0
|
|
|
0
|
$in ||= $self->_get_readline(); |
2399
|
|
|
|
|
|
|
|
2400
|
|
|
|
|
|
|
# Some options get processed before we initialize. |
2401
|
0
|
|
|
|
|
0
|
foreach my $name ( qw{ echo filter } ) { |
2402
|
|
|
|
|
|
|
exists $opt{$name} |
2403
|
0
|
0
|
|
|
|
0
|
and $self->set( $name => delete( $opt{$name} ) ); |
2404
|
|
|
|
|
|
|
} |
2405
|
|
|
|
|
|
|
|
2406
|
|
|
|
|
|
|
# Display the front matter if desired. |
2407
|
0
|
0
|
0
|
|
|
0
|
(!$self->get('filter') && $self->_get_interactive()) |
2408
|
|
|
|
|
|
|
and print $self->version(); |
2409
|
|
|
|
|
|
|
|
2410
|
|
|
|
|
|
|
# Execute the initialization file. |
2411
|
0
|
0
|
|
|
|
0
|
eval { |
2412
|
|
|
|
|
|
|
$self->_execute_output( $self->init( |
2413
|
|
|
|
|
|
|
{ level1 => delete $opt{level1} }, |
2414
|
|
|
|
|
|
|
delete $opt{initialization_file}, |
2415
|
0
|
|
|
|
|
0
|
), $self->get( 'stdout' ) ); |
2416
|
0
|
|
|
|
|
0
|
1; |
2417
|
|
|
|
|
|
|
} or warn $@; # Not whinge, since presumably we already did. |
2418
|
|
|
|
|
|
|
|
2419
|
|
|
|
|
|
|
# The remaining options set the corresponding attributes. |
2420
|
0
|
0
|
|
|
|
0
|
%opt and $self->set(%opt); |
2421
|
|
|
|
|
|
|
|
2422
|
|
|
|
|
|
|
# Execution loop. What exit() really does is a last on this. |
2423
|
|
|
|
|
|
|
SATPASS2_EXECUTE: |
2424
|
|
|
|
|
|
|
{ |
2425
|
0
|
|
|
|
|
0
|
$self->_execute( @args ); |
|
0
|
|
|
|
|
0
|
|
2426
|
0
|
|
|
|
|
0
|
while ( defined ( my $buffer = $in->( $self->get( 'prompt' ) ) ) ) { |
2427
|
0
|
|
|
|
|
0
|
$self->_execute( $in, $buffer ); |
2428
|
|
|
|
|
|
|
} |
2429
|
|
|
|
|
|
|
} |
2430
|
0
|
|
|
|
|
0
|
$self->_execute( q{echo ''} ); # The lazy way to be sure we |
2431
|
|
|
|
|
|
|
# have a newline before exit. |
2432
|
0
|
|
|
|
|
0
|
return; |
2433
|
|
|
|
|
|
|
} |
2434
|
|
|
|
|
|
|
} |
2435
|
|
|
|
|
|
|
|
2436
|
|
|
|
|
|
|
sub save : Verb( changes! overwrite! ) { |
2437
|
0
|
|
|
0
|
1
|
0
|
my ( $self, $opt, $fn ) = __arguments( @_ ); |
2438
|
|
|
|
|
|
|
|
2439
|
0
|
0
|
|
|
|
0
|
defined $fn or $fn = $self->initfile( { 'create-directory' => 1 } ); |
2440
|
0
|
|
|
|
|
0
|
chomp $fn; # because initfile() adds a newline for printing |
2441
|
0
|
0
|
0
|
|
|
0
|
if ($fn ne '-' && -e $fn) { |
2442
|
0
|
0
|
|
|
|
0
|
-f $fn or $self->wail( |
2443
|
|
|
|
|
|
|
"Can not overwrite $fn: not an ordinary file"); |
2444
|
0
|
0
|
|
|
|
0
|
$opt->{overwrite} or do { |
2445
|
0
|
|
|
|
|
0
|
my $rslt = $self->_get_readline()->( |
2446
|
|
|
|
|
|
|
"File $fn exists. Overwrite [y/N]? "); |
2447
|
0
|
0
|
|
|
|
0
|
'y' eq lc substr($rslt, 0, 1) |
2448
|
|
|
|
|
|
|
or return; |
2449
|
|
|
|
|
|
|
}; |
2450
|
|
|
|
|
|
|
} |
2451
|
0
|
|
|
|
|
0
|
my @show_opt; |
2452
|
0
|
|
|
|
|
0
|
my $title = 'settings'; |
2453
|
0
|
0
|
|
|
|
0
|
if ($opt->{changes}) { |
2454
|
0
|
|
|
|
|
0
|
push @show_opt, '-changes'; |
2455
|
0
|
|
|
|
|
0
|
$title = 'setting changes'; |
2456
|
|
|
|
|
|
|
} |
2457
|
|
|
|
|
|
|
|
2458
|
0
|
|
|
|
|
0
|
my $output = <<"EOD" . |
2459
|
|
|
|
|
|
|
|
2460
|
|
|
|
|
|
|
# Astro::App::Satpass2 $title |
2461
|
|
|
|
|
|
|
|
2462
|
|
|
|
|
|
|
EOD |
2463
|
|
|
|
|
|
|
$self->show( @show_opt, qw{ -nodeprecated -noreadonly } ) . |
2464
|
|
|
|
|
|
|
<<"EOD" . $self->macro('list'); |
2465
|
|
|
|
|
|
|
|
2466
|
|
|
|
|
|
|
# Astro::App::Satpass2 macros |
2467
|
|
|
|
|
|
|
|
2468
|
|
|
|
|
|
|
EOD |
2469
|
|
|
|
|
|
|
|
2470
|
0
|
0
|
|
|
|
0
|
if ( $self->{_perl} ) { |
2471
|
0
|
|
|
|
|
0
|
$output .= <<'EOD'; |
2472
|
|
|
|
|
|
|
|
2473
|
|
|
|
|
|
|
# Astro::App::Satpass2 setup |
2474
|
|
|
|
|
|
|
|
2475
|
|
|
|
|
|
|
EOD |
2476
|
0
|
|
|
|
|
0
|
foreach my $item ( @{ $self->{_perl} } ) { |
|
0
|
|
|
|
|
0
|
|
2477
|
0
|
|
|
|
|
0
|
my ( $opt, @arg ) = @{ $item }; |
|
0
|
|
|
|
|
0
|
|
2478
|
0
|
|
|
|
|
0
|
my @cmd = ( 'perl' ); |
2479
|
0
|
|
|
|
|
0
|
push @cmd, map { "-$_" } grep { $opt->{$_} } sort keys %{ $opt }; |
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
2480
|
0
|
|
|
|
|
0
|
$output .= join ' ', quoter( @cmd, @arg ); |
2481
|
0
|
|
|
|
|
0
|
$output .= "\n"; |
2482
|
|
|
|
|
|
|
} |
2483
|
|
|
|
|
|
|
} |
2484
|
|
|
|
|
|
|
|
2485
|
0
|
|
|
|
|
0
|
foreach my $attribute ( qw{ formatter spacetrack time_parser } ) { |
2486
|
0
|
0
|
|
|
|
0
|
my $obj = $self->get( $attribute ) or next; |
2487
|
0
|
0
|
0
|
|
|
0
|
my $class = $obj->can( 'class_name_of_record' ) ? |
2488
|
|
|
|
|
|
|
$obj->class_name_of_record() : |
2489
|
|
|
|
|
|
|
ref $obj || $obj; |
2490
|
0
|
|
0
|
|
|
0
|
$output .= <<"EOD" . |
2491
|
|
|
|
|
|
|
|
2492
|
|
|
|
|
|
|
# $class $title |
2493
|
|
|
|
|
|
|
|
2494
|
|
|
|
|
|
|
EOD |
2495
|
|
|
|
|
|
|
( $self->$attribute( $opt, 'config' ) || "# none\n" ); |
2496
|
|
|
|
|
|
|
} |
2497
|
|
|
|
|
|
|
|
2498
|
0
|
|
|
|
|
0
|
$output .= $self->_save_sky( $opt ); |
2499
|
|
|
|
|
|
|
|
2500
|
0
|
0
|
|
|
|
0
|
if ($fn ne '-') { |
2501
|
0
|
0
|
|
|
|
0
|
my $fh = IO::File->new( $fn, '>:encoding(utf-8)') |
2502
|
|
|
|
|
|
|
or $self->wail("Unable to open $fn: $!"); |
2503
|
0
|
|
|
|
|
0
|
print { $fh } $output; |
|
0
|
|
|
|
|
0
|
|
2504
|
0
|
|
|
|
|
0
|
$output = "$fn\n"; |
2505
|
|
|
|
|
|
|
} |
2506
|
0
|
|
|
|
|
0
|
return $output; |
2507
|
20
|
|
|
20
|
|
21773
|
} |
|
20
|
|
|
|
|
60
|
|
|
20
|
|
|
|
|
110
|
|
2508
|
|
|
|
|
|
|
|
2509
|
|
|
|
|
|
|
# Formats the commands to reconstitute the sky. This is only called from |
2510
|
|
|
|
|
|
|
# save(), but it is a subroutine for organizational reasons. |
2511
|
|
|
|
|
|
|
sub _save_sky { |
2512
|
0
|
|
|
0
|
|
0
|
my ( $self, $opt ) = @_; |
2513
|
|
|
|
|
|
|
|
2514
|
0
|
|
|
|
|
0
|
my $output = <<'EOD'; |
2515
|
|
|
|
|
|
|
|
2516
|
|
|
|
|
|
|
# Astro::App::Satpass2 sky |
2517
|
|
|
|
|
|
|
|
2518
|
|
|
|
|
|
|
EOD |
2519
|
|
|
|
|
|
|
|
2520
|
0
|
|
|
|
|
0
|
foreach my $body ( sort keys %{ $self->{sky_class} } ) { |
|
0
|
|
|
|
|
0
|
|
2521
|
|
|
|
|
|
|
$opt->{changes} |
2522
|
|
|
|
|
|
|
and $sky_class{$body} |
2523
|
0
|
0
|
0
|
|
|
0
|
and $sky_class{$body} eq $self->{sky_class}{$body} |
|
|
|
0
|
|
|
|
|
2524
|
|
|
|
|
|
|
and next; |
2525
|
0
|
|
|
|
|
0
|
$output .= $self->_sky_class_components( $body ) . "\n"; |
2526
|
|
|
|
|
|
|
} |
2527
|
0
|
|
|
|
|
0
|
foreach my $body ( sort keys ( %sky_class ) ) { |
2528
|
0
|
0
|
|
|
|
0
|
$self->{sky_class}{$body} |
2529
|
|
|
|
|
|
|
or $output .= $self->_sky_class_components( $body ) . "\n"; |
2530
|
|
|
|
|
|
|
} |
2531
|
|
|
|
|
|
|
|
2532
|
0
|
|
|
|
|
0
|
my %exclude; |
2533
|
0
|
0
|
|
|
|
0
|
if ( $opt->{changes} ) { |
2534
|
0
|
|
|
|
|
0
|
%exclude = map { $_ => 1 } |
|
0
|
|
|
|
|
0
|
|
2535
|
|
|
|
|
|
|
SUN_CLASS_DEFAULT, 'Astro::Coord::ECI::Moon'; |
2536
|
0
|
|
|
|
|
0
|
foreach my $name ( qw{ sun moon } ) { |
2537
|
0
|
0
|
|
|
|
0
|
defined $self->_find_in_sky( $name ) |
2538
|
|
|
|
|
|
|
or $output .= "sky drop $name\n"; |
2539
|
|
|
|
|
|
|
} |
2540
|
|
|
|
|
|
|
} else { |
2541
|
0
|
|
|
|
|
0
|
$output .= "sky clear\n"; |
2542
|
|
|
|
|
|
|
} |
2543
|
0
|
|
|
|
|
0
|
foreach my $body ( @{ $self->{sky} } ) { |
|
0
|
|
|
|
|
0
|
|
2544
|
0
|
0
|
|
|
|
0
|
$exclude{ ref $body } |
2545
|
|
|
|
|
|
|
and next; |
2546
|
0
|
|
|
|
|
0
|
$output .= _sky_list_body( $body ); |
2547
|
|
|
|
|
|
|
} |
2548
|
|
|
|
|
|
|
|
2549
|
0
|
|
|
|
|
0
|
return $output; |
2550
|
|
|
|
|
|
|
} |
2551
|
|
|
|
|
|
|
|
2552
|
|
|
|
|
|
|
sub set : Verb() { |
2553
|
72
|
|
|
72
|
1
|
403
|
my ( $self, undef, @args ) = __arguments( @_ ); # $opt unused |
2554
|
|
|
|
|
|
|
|
2555
|
72
|
|
|
|
|
329
|
while (@args) { |
2556
|
351
|
|
|
|
|
926
|
my ( $name, $value ) = splice @args, 0, 2; |
2557
|
351
|
|
|
|
|
1017
|
$self->_attribute_exists( $name ); |
2558
|
351
|
100
|
|
|
|
743
|
if ( _is_interactive() ) { |
2559
|
28
|
100
|
|
|
|
155
|
$nointeractive{$name} |
2560
|
|
|
|
|
|
|
and $self->wail( |
2561
|
|
|
|
|
|
|
"Attribute '$name' may not be set interactively"); |
2562
|
27
|
50
|
66
|
|
|
188
|
defined $value and $value eq 'undef' |
2563
|
|
|
|
|
|
|
and $value = undef; |
2564
|
|
|
|
|
|
|
} |
2565
|
350
|
50
|
|
|
|
1083
|
if ( $mutator{$name} ) { |
2566
|
350
|
|
|
|
|
925
|
$self->_deprecation_notice( attribute => $name ); |
2567
|
350
|
|
|
|
|
1024
|
$mutator{$name}->($self, $name, $value); |
2568
|
|
|
|
|
|
|
} else { |
2569
|
0
|
|
|
|
|
0
|
$self->wail("Read-only attribute '$name'"); |
2570
|
|
|
|
|
|
|
} |
2571
|
|
|
|
|
|
|
} |
2572
|
71
|
|
|
|
|
207
|
return; |
2573
|
20
|
|
|
20
|
|
13428
|
} |
|
20
|
|
|
|
|
65
|
|
|
20
|
|
|
|
|
101
|
|
2574
|
|
|
|
|
|
|
|
2575
|
|
|
|
|
|
|
sub _set_almanac_horizon { |
2576
|
7
|
|
|
7
|
|
30
|
my ( $self, $name, $value ) = @_; |
2577
|
7
|
|
|
|
|
43
|
my $parsed = $self->__parse_angle( { accept => 1 }, $value ); |
2578
|
7
|
50
|
|
|
|
83
|
my $internal = looks_like_number( $parsed ) ? deg2rad( $parsed ) : |
2579
|
|
|
|
|
|
|
$parsed; |
2580
|
7
|
|
|
|
|
169
|
my $eci = Astro::Coord::ECI->new(); |
2581
|
7
|
|
|
|
|
640
|
$eci->set( $name => $internal ); # To validate. |
2582
|
7
|
|
|
|
|
290
|
$self->{"_$name"} = $internal; |
2583
|
7
|
|
|
|
|
86
|
return( $self->{$name} = $parsed ); |
2584
|
|
|
|
|
|
|
} |
2585
|
|
|
|
|
|
|
|
2586
|
|
|
|
|
|
|
{ |
2587
|
|
|
|
|
|
|
my $plus_or_minus_90 = sub { $_[0] >= -90 && $_[0] <= 90 }; |
2588
|
|
|
|
|
|
|
my %validate = ( |
2589
|
|
|
|
|
|
|
horizon => $plus_or_minus_90, |
2590
|
|
|
|
|
|
|
latitude => $plus_or_minus_90, |
2591
|
|
|
|
|
|
|
longitude => sub { |
2592
|
|
|
|
|
|
|
$_[0] > 360 |
2593
|
|
|
|
|
|
|
and return 0; |
2594
|
|
|
|
|
|
|
$_[0] > 180 |
2595
|
|
|
|
|
|
|
and $_[0] -= 360; |
2596
|
|
|
|
|
|
|
$_[0] >= -180 && $_[0] <= 180; |
2597
|
|
|
|
|
|
|
}, |
2598
|
|
|
|
|
|
|
); |
2599
|
|
|
|
|
|
|
sub _set_angle { |
2600
|
31
|
|
|
31
|
|
124
|
my ( $self, $name, $value ) = @_; |
2601
|
31
|
|
|
|
|
99
|
my $angle = $self->__parse_angle( $value ); |
2602
|
31
|
100
|
|
|
|
151
|
if ( my $code = $validate{$name} ) { |
2603
|
15
|
0
|
|
|
|
57
|
defined $angle or $self->weep( |
|
|
50
|
|
|
|
|
|
2604
|
|
|
|
|
|
|
"$name angle is undef for value ", defined $value ? $value : 'undef' ); |
2605
|
15
|
50
|
|
|
|
71
|
$code->( $angle ) |
2606
|
|
|
|
|
|
|
or $self->wail( "Value $value is invalid for $name" ); |
2607
|
|
|
|
|
|
|
} |
2608
|
31
|
|
|
|
|
137
|
$self->{"_$name"} = deg2rad( $angle ); |
2609
|
31
|
|
|
|
|
356
|
return ( $self->{$name} = $angle ); |
2610
|
|
|
|
|
|
|
} |
2611
|
|
|
|
|
|
|
} |
2612
|
|
|
|
|
|
|
|
2613
|
|
|
|
|
|
|
sub _set_angle_or_undef { |
2614
|
21
|
|
|
21
|
|
66
|
my ( $self, $name, $value ) = @_; |
2615
|
21
|
100
|
66
|
|
|
122
|
defined $value and 'undef' ne $value and goto &_set_angle; |
2616
|
15
|
|
|
|
|
63
|
return ( $self->{$name} = undef ); |
2617
|
|
|
|
|
|
|
} |
2618
|
|
|
|
|
|
|
|
2619
|
|
|
|
|
|
|
sub _set_code_ref { |
2620
|
11
|
50
|
|
11
|
|
62
|
CODE_REF eq ref $_[2] |
2621
|
|
|
|
|
|
|
or $_[0]->wail( "Attribute $_[1] must be a code reference" ); |
2622
|
11
|
|
|
|
|
57
|
return( $_[0]{$_[1]} = $_[2] ); |
2623
|
|
|
|
|
|
|
} |
2624
|
|
|
|
|
|
|
|
2625
|
|
|
|
|
|
|
# Set an attribute whose value is an Astro::App::Satpass2::Copier object |
2626
|
|
|
|
|
|
|
# %arg is a hash of argument name/value pairs: |
2627
|
|
|
|
|
|
|
# {name} is the required name of the attribute to set; |
2628
|
|
|
|
|
|
|
# {value} is the required value of the attribute to set; |
2629
|
|
|
|
|
|
|
# {class} is the optional class that the object must be; |
2630
|
|
|
|
|
|
|
# {default} is the optional default value if the required value is |
2631
|
|
|
|
|
|
|
# undef or ''; |
2632
|
|
|
|
|
|
|
# {undefined} is an optional value which, if true, permits the |
2633
|
|
|
|
|
|
|
# attribute to be set to undef; |
2634
|
|
|
|
|
|
|
# {nocopy} is an optional value which, if true, causes the old |
2635
|
|
|
|
|
|
|
# object's attributes not to be copied to the new object; |
2636
|
|
|
|
|
|
|
# {message} is an optional message to emit if the object can not be |
2637
|
|
|
|
|
|
|
# instantiated; |
2638
|
|
|
|
|
|
|
# {prefix} is an optional reference to an array of name prefixes to |
2639
|
|
|
|
|
|
|
# try if the named module does not load. |
2640
|
|
|
|
|
|
|
|
2641
|
|
|
|
|
|
|
sub _set_copyable { |
2642
|
14
|
|
|
14
|
|
99
|
my ( $self, %arg ) = @_; |
2643
|
14
|
|
|
|
|
53
|
my $old = $self->{$arg{name}}; |
2644
|
14
|
|
|
|
|
30
|
my $obj; |
2645
|
14
|
50
|
|
|
|
59
|
if ( ref $arg{value} ) { |
2646
|
|
|
|
|
|
|
blessed( $arg{value} ) |
2647
|
0
|
0
|
|
|
|
0
|
or $self->wail( "$arg{name} may not be unblessed reference" ); |
2648
|
0
|
|
|
|
|
0
|
$obj = $arg{value}; |
2649
|
|
|
|
|
|
|
$obj->can( 'warner' ) |
2650
|
0
|
0
|
|
|
|
0
|
and $obj->warner( $self->{_warner} ); |
2651
|
|
|
|
|
|
|
} else { |
2652
|
14
|
50
|
|
|
|
54
|
if ( defined $arg{default} ) { |
2653
|
|
|
|
|
|
|
defined $arg{value} |
2654
|
|
|
|
|
|
|
and '' ne $arg{value} |
2655
|
14
|
50
|
33
|
|
|
93
|
or $arg{value} = $arg{default}; |
2656
|
|
|
|
|
|
|
} |
2657
|
14
|
50
|
33
|
|
|
113
|
if ( ! defined $arg{value} || $arg{value} eq '' ) { |
2658
|
|
|
|
|
|
|
$arg{undefined} |
2659
|
0
|
0
|
|
|
|
0
|
or $self->wail( |
2660
|
|
|
|
|
|
|
"$arg{name} must be defined and not empty", |
2661
|
|
|
|
|
|
|
); |
2662
|
0
|
|
|
|
|
0
|
return ( $self->{$arg{name}} = $arg{value} = undef ); |
2663
|
|
|
|
|
|
|
} |
2664
|
14
|
|
|
|
|
88
|
my ( $pkg, @args ) = $self->__parse_class_and_args( $arg{value} ); |
2665
|
|
|
|
|
|
|
my $cls = $self->load_package( |
2666
|
14
|
50
|
|
|
|
59
|
{ fatal => 'wail' }, $pkg, @{ $arg{prefix} || [] } ); |
|
14
|
|
|
|
|
108
|
|
2667
|
14
|
50
|
33
|
|
|
223
|
not $cls->can( 'init' ) |
2668
|
|
|
|
|
|
|
and _is_case_tolerant() |
2669
|
|
|
|
|
|
|
and $self->wail( |
2670
|
|
|
|
|
|
|
"$cls is missing methods. This can happen on a ", |
2671
|
|
|
|
|
|
|
'case-tolerant system if you specify the class ', |
2672
|
|
|
|
|
|
|
'name in the wrong case.' ); |
2673
|
14
|
100
|
|
|
|
133
|
$cls->can( 'parent' ) |
2674
|
|
|
|
|
|
|
and push @args, parent => $self; |
2675
|
|
|
|
|
|
|
$obj = $cls->new( |
2676
|
|
|
|
|
|
|
warner => $self->{_warner}, |
2677
|
|
|
|
|
|
|
@args, |
2678
|
|
|
|
|
|
|
) |
2679
|
|
|
|
|
|
|
or $self->wail( $arg{message} || |
2680
|
14
|
50
|
0
|
|
|
97
|
"Can not instantiate object from '$arg{value}'" ); |
2681
|
|
|
|
|
|
|
} |
2682
|
|
|
|
|
|
|
defined $arg{class} |
2683
|
|
|
|
|
|
|
and not $obj->isa( $arg{class} ) |
2684
|
14
|
50
|
66
|
|
|
131
|
and $self->wail( "$arg{name} must be of class $arg{class}" ); |
2685
|
|
|
|
|
|
|
blessed( $old ) |
2686
|
|
|
|
|
|
|
and not $arg{nocopy} |
2687
|
14
|
0
|
33
|
|
|
78
|
and $old->can( 'copy' ) |
|
|
|
33
|
|
|
|
|
2688
|
|
|
|
|
|
|
and $old->copy( $obj ); |
2689
|
14
|
|
|
|
|
115
|
$self->{$arg{name}} = $obj; |
2690
|
14
|
|
|
|
|
103
|
return $arg{value}; |
2691
|
|
|
|
|
|
|
} |
2692
|
|
|
|
|
|
|
|
2693
|
|
|
|
|
|
|
sub _set_distance_meters { |
2694
|
9
|
100
|
|
9
|
|
58
|
return ( $_[0]{$_[1]} = defined $_[2] ? |
2695
|
|
|
|
|
|
|
( $_[0]->__parse_distance( $_[2], '0m' ) * 1000 ) : $_[2] ); |
2696
|
|
|
|
|
|
|
} |
2697
|
|
|
|
|
|
|
|
2698
|
|
|
|
|
|
|
sub _set_ellipsoid { |
2699
|
7
|
|
|
7
|
|
36
|
my ($self, $name, $val) = @_; |
2700
|
7
|
|
|
|
|
90
|
Astro::Coord::ECI->set (ellipsoid => $val); |
2701
|
7
|
|
|
|
|
326
|
return ($self->{$name} = $val); |
2702
|
|
|
|
|
|
|
} |
2703
|
|
|
|
|
|
|
|
2704
|
|
|
|
|
|
|
sub _set_formatter { |
2705
|
7
|
|
|
7
|
|
24
|
my ( $self, $name, $val ) = @_; |
2706
|
7
|
|
|
|
|
43
|
return $self->_set_copyable( |
2707
|
|
|
|
|
|
|
name => $name, |
2708
|
|
|
|
|
|
|
value => $val, |
2709
|
|
|
|
|
|
|
message => 'Unknown formatter', |
2710
|
|
|
|
|
|
|
default => 'Astro::App::Satpass2::Format::Template', |
2711
|
|
|
|
|
|
|
prefix => [ 'Astro::App::Satpass2::Format' ] |
2712
|
|
|
|
|
|
|
); |
2713
|
|
|
|
|
|
|
} |
2714
|
|
|
|
|
|
|
|
2715
|
|
|
|
|
|
|
sub _set_formatter_attribute { |
2716
|
24
|
|
|
24
|
|
79
|
my ( $self, $name, $val ) = @_; |
2717
|
24
|
|
|
|
|
67
|
$self->get( 'formatter' )->$name( $val ); |
2718
|
24
|
|
|
|
|
83
|
return $val; |
2719
|
|
|
|
|
|
|
} |
2720
|
|
|
|
|
|
|
|
2721
|
|
|
|
|
|
|
sub _set_geocoder { |
2722
|
0
|
|
|
0
|
|
0
|
my ( $self, $name, $val ) = @_; |
2723
|
0
|
|
|
|
|
0
|
return $self->_set_copyable( |
2724
|
|
|
|
|
|
|
name => $name, |
2725
|
|
|
|
|
|
|
value => $val, |
2726
|
|
|
|
|
|
|
class => 'Astro::App::Satpass2::Geocode', |
2727
|
|
|
|
|
|
|
message => 'Unknown formatter', |
2728
|
|
|
|
|
|
|
default => $default_geocoder->(), |
2729
|
|
|
|
|
|
|
undefined => 1, |
2730
|
|
|
|
|
|
|
nocopy => 1, |
2731
|
|
|
|
|
|
|
prefix => [ 'Astro::App::Satpass2::Geocode' ] |
2732
|
|
|
|
|
|
|
); |
2733
|
|
|
|
|
|
|
} |
2734
|
|
|
|
|
|
|
|
2735
|
|
|
|
|
|
|
sub _set_illum_class { |
2736
|
7
|
|
|
7
|
|
38
|
my ( $self, $name, $class ) = @_; |
2737
|
7
|
|
|
|
|
19
|
my $want_class = 'Astro::Coord::ECI'; |
2738
|
7
|
50
|
|
|
|
29
|
ref $class and $self->wail( "$name must not be a reference" ); |
2739
|
7
|
50
|
|
|
|
31
|
if ( defined $class ) { |
2740
|
7
|
|
|
|
|
63
|
$self->load_package( { fatal => 'wail' }, $class ); |
2741
|
7
|
50
|
|
|
|
86
|
$class->isa( $want_class ) |
2742
|
|
|
|
|
|
|
or $self->wail( "$name must be an $want_class" ); |
2743
|
|
|
|
|
|
|
} else { |
2744
|
0
|
|
|
|
|
0
|
$class = $want_class; |
2745
|
|
|
|
|
|
|
} |
2746
|
7
|
|
|
|
|
31
|
$self->{$name} = $class; |
2747
|
7
|
|
|
|
|
26
|
$self->{_help_module}{$name} = $class; |
2748
|
7
|
|
|
|
|
16
|
foreach my $body ( @{ $self->{bodies} } ) { |
|
7
|
|
|
|
|
36
|
|
2749
|
0
|
|
|
|
|
0
|
$body->set( $name => $class ); |
2750
|
|
|
|
|
|
|
} |
2751
|
7
|
|
|
|
|
27
|
return; |
2752
|
|
|
|
|
|
|
} |
2753
|
|
|
|
|
|
|
|
2754
|
|
|
|
|
|
|
sub _set_model { |
2755
|
7
|
|
|
7
|
|
39
|
my ( $self, $name, $val ) = @_; |
2756
|
7
|
50
|
|
|
|
65
|
Astro::Coord::ECI::TLE->is_valid_model( $val ) |
2757
|
|
|
|
|
|
|
or $self->wail( |
2758
|
|
|
|
|
|
|
"'$val' is not a valid Astro::Coord::ECI::TLE model" ); |
2759
|
7
|
|
|
|
|
53
|
foreach my $body ( @{ $self->{bodies} } ) { |
|
7
|
|
|
|
|
29
|
|
2760
|
0
|
|
|
|
|
0
|
$body->set( model => $val ); |
2761
|
|
|
|
|
|
|
} |
2762
|
7
|
|
|
|
|
50
|
return ( $self->{$name} = $val ); |
2763
|
|
|
|
|
|
|
} |
2764
|
|
|
|
|
|
|
|
2765
|
|
|
|
|
|
|
sub _set_output_layers { |
2766
|
7
|
|
|
7
|
|
23
|
my ( $self, $name, $val ) = @_; |
2767
|
|
|
|
|
|
|
|
2768
|
7
|
50
|
33
|
|
|
52
|
if ( defined $val && '' ne $val ) { |
2769
|
7
|
50
|
|
7
|
|
64
|
open my $fh, ">$val", File::Spec->devnull() |
|
7
|
|
|
|
|
19
|
|
|
7
|
|
|
|
|
60
|
|
|
7
|
|
|
|
|
426
|
|
2770
|
|
|
|
|
|
|
or $self->wail( "Invalid $name value '$val'" ); |
2771
|
7
|
|
|
|
|
81759
|
close $fh; |
2772
|
|
|
|
|
|
|
} |
2773
|
7
|
|
|
|
|
95
|
return ( $self->{$name} = $val ); |
2774
|
|
|
|
|
|
|
} |
2775
|
|
|
|
|
|
|
|
2776
|
|
|
|
|
|
|
{ |
2777
|
|
|
|
|
|
|
my %variant_def = ( |
2778
|
|
|
|
|
|
|
visible_events => PASS_VARIANT_VISIBLE_EVENTS, |
2779
|
|
|
|
|
|
|
fake_max => PASS_VARIANT_FAKE_MAX, |
2780
|
|
|
|
|
|
|
start_end => PASS_VARIANT_START_END, |
2781
|
|
|
|
|
|
|
no_illumination => PASS_VARIANT_NO_ILLUMINATION, |
2782
|
|
|
|
|
|
|
brightest => PASS_VARIANT_BRIGHTEST, |
2783
|
|
|
|
|
|
|
); |
2784
|
|
|
|
|
|
|
|
2785
|
|
|
|
|
|
|
my @option_names; |
2786
|
|
|
|
|
|
|
foreach my $key ( keys %variant_def ) { |
2787
|
|
|
|
|
|
|
if ( $key =~ m/ _ /smx ) { |
2788
|
|
|
|
|
|
|
( my $dashed = $key ) =~ s/ _ /-/smxg; |
2789
|
|
|
|
|
|
|
$key = "$key|$dashed"; |
2790
|
|
|
|
|
|
|
} |
2791
|
|
|
|
|
|
|
push @option_names, "$key!"; |
2792
|
|
|
|
|
|
|
} |
2793
|
|
|
|
|
|
|
|
2794
|
|
|
|
|
|
|
my $go; |
2795
|
|
|
|
|
|
|
|
2796
|
|
|
|
|
|
|
sub _set_pass_variant { |
2797
|
8
|
|
|
8
|
|
28
|
my ( $self, $name, $val ) = @_; |
2798
|
8
|
100
|
|
|
|
70
|
if ( $val =~ m/ \A (?: 0 x? ) [0-9]* \z /smx ) { |
|
|
50
|
|
|
|
|
|
2799
|
7
|
|
|
|
|
39
|
$val = oct $val; |
2800
|
|
|
|
|
|
|
} elsif ( $val !~ m/ \A [0-9]+ \z /smx ) { |
2801
|
1
|
|
|
|
|
10
|
my @args = split qr{ [^\w-] }smx, $val; |
2802
|
1
|
|
|
|
|
4
|
foreach ( @args ) { |
2803
|
1
|
|
|
|
|
6
|
s/ \A (?! - ) /-/smx; |
2804
|
|
|
|
|
|
|
} |
2805
|
1
|
|
33
|
|
|
14
|
$go ||= Getopt::Long::Parser->new(); |
2806
|
1
|
|
|
|
|
23
|
$val = $self->get( $name ); |
2807
|
|
|
|
|
|
|
$go->getoptionsfromarray( \@args, |
2808
|
0
|
|
|
0
|
|
0
|
none => sub { $val = PASS_VARIANT_NONE }, |
2809
|
1
|
50
|
|
|
|
12
|
map { $_ => sub { |
2810
|
1
|
|
|
1
|
|
644
|
my ( $name, $value ) = @_; |
2811
|
1
|
|
|
|
|
6
|
my $mask = $variant_def{$name}; |
2812
|
1
|
50
|
|
|
|
10
|
if ( $value ) { |
2813
|
0
|
|
|
|
|
0
|
$val |= $mask; |
2814
|
|
|
|
|
|
|
} else { |
2815
|
1
|
|
|
|
|
4
|
$val &= ~ $mask; |
2816
|
|
|
|
|
|
|
} |
2817
|
1
|
|
|
|
|
3
|
return; |
2818
|
|
|
|
|
|
|
} |
2819
|
5
|
|
|
|
|
22
|
} @option_names ) |
2820
|
|
|
|
|
|
|
or $self->wail( "Invalid $name value '$val'" ); |
2821
|
|
|
|
|
|
|
} |
2822
|
8
|
|
|
|
|
130
|
return ( $self->{$name} = $val ); |
2823
|
|
|
|
|
|
|
} |
2824
|
|
|
|
|
|
|
|
2825
|
|
|
|
|
|
|
sub _show_pass_variant { |
2826
|
1
|
|
|
1
|
|
3
|
my ( $self, $name ) = @_; |
2827
|
1
|
|
|
|
|
6
|
my $val = $self->get( $name ); |
2828
|
1
|
|
|
|
|
4
|
my @options; |
2829
|
1
|
|
|
|
|
22
|
foreach my $key ( keys %variant_def ) { |
2830
|
5
|
50
|
|
|
|
17
|
$val & $variant_def{$key} |
2831
|
|
|
|
|
|
|
and push @options, "$key"; |
2832
|
|
|
|
|
|
|
} |
2833
|
|
|
|
|
|
|
@options |
2834
|
1
|
50
|
|
|
|
8
|
or push @options, 'none'; |
2835
|
1
|
|
|
|
|
6
|
return ( set => $name, join ',', @options ); |
2836
|
|
|
|
|
|
|
} |
2837
|
|
|
|
|
|
|
|
2838
|
|
|
|
|
|
|
sub want_pass_variant { |
2839
|
138
|
|
|
138
|
1
|
2512
|
my ( $self, $variant ) = @_; |
2840
|
138
|
50
|
|
|
|
486
|
$variant_def{$variant} |
2841
|
|
|
|
|
|
|
or $self->wail( "Invalid pass_variant name '$variant'" ); |
2842
|
138
|
|
|
|
|
411
|
my $val = $self->get( 'pass_variant' ) & $variant_def{$variant}; |
2843
|
138
|
|
|
|
|
387
|
return $val; |
2844
|
|
|
|
|
|
|
} |
2845
|
|
|
|
|
|
|
|
2846
|
|
|
|
|
|
|
} |
2847
|
|
|
|
|
|
|
|
2848
|
|
|
|
|
|
|
sub _set_spacetrack { |
2849
|
0
|
|
|
0
|
|
0
|
my ($self, $name, $val) = @_; |
2850
|
0
|
0
|
|
|
|
0
|
if (defined $val) { |
2851
|
0
|
0
|
|
|
|
0
|
instance($val, 'Astro::SpaceTrack') |
2852
|
|
|
|
|
|
|
or $self->wail("$name must be an Astro::SpaceTrack instance"); |
2853
|
0
|
|
|
|
|
0
|
my $version = $val->VERSION(); |
2854
|
0
|
|
|
|
|
0
|
$version =~ s/ _ //smxg; |
2855
|
0
|
0
|
|
|
|
0
|
$version >= ASTRO_SPACETRACK_VERSION |
2856
|
|
|
|
|
|
|
or $self->wail("$name must be Astro::SpaceTrack version ", |
2857
|
|
|
|
|
|
|
ASTRO_SPACETRACK_VERSION, ' or greater' ); |
2858
|
|
|
|
|
|
|
} |
2859
|
0
|
|
|
|
|
0
|
return ($self->{$name} = $val); |
2860
|
|
|
|
|
|
|
} |
2861
|
|
|
|
|
|
|
|
2862
|
|
|
|
|
|
|
sub _set_stdout { |
2863
|
15
|
|
|
15
|
|
44
|
my ($self, $name, $val) = @_; |
2864
|
|
|
|
|
|
|
$self->{frame} |
2865
|
15
|
50
|
|
|
|
66
|
and $self->{frame}[-1]{$name} = $val; |
2866
|
15
|
|
|
|
|
58
|
return ($self->{$name} = $val); |
2867
|
|
|
|
|
|
|
} |
2868
|
|
|
|
|
|
|
|
2869
|
|
|
|
|
|
|
sub _set_sun_class { |
2870
|
0
|
|
|
0
|
|
0
|
my ( $self, $name, $val ) = @_; |
2871
|
0
|
|
|
|
|
0
|
$self->_attribute_exists( $name ); |
2872
|
0
|
|
|
|
|
0
|
return $self->sky( class => $name, $val ); |
2873
|
|
|
|
|
|
|
} |
2874
|
|
|
|
|
|
|
|
2875
|
|
|
|
|
|
|
sub _set_time_parser { |
2876
|
7
|
|
|
7
|
|
27
|
my ( $self, $name, $val ) = @_; |
2877
|
|
|
|
|
|
|
|
2878
|
7
|
50
|
33
|
|
|
72
|
if ( CODE_REF eq ref $val ) { |
|
|
50
|
|
|
|
|
|
2879
|
0
|
|
|
|
|
0
|
$val = _set_time_parser_code( $val ); |
2880
|
|
|
|
|
|
|
} elsif ( defined $val and my $macro = $self->{macro}{$val} ) { |
2881
|
0
|
|
|
|
|
0
|
$val = _set_time_parser_code( |
2882
|
|
|
|
|
|
|
$macro->implements( $val, required => 1 ), |
2883
|
|
|
|
|
|
|
$val, |
2884
|
|
|
|
|
|
|
); |
2885
|
|
|
|
|
|
|
} |
2886
|
|
|
|
|
|
|
|
2887
|
7
|
|
|
|
|
61
|
return $self->_set_copyable( |
2888
|
|
|
|
|
|
|
name => $name, |
2889
|
|
|
|
|
|
|
value => $val, |
2890
|
|
|
|
|
|
|
class => 'Astro::App::Satpass2::ParseTime', |
2891
|
|
|
|
|
|
|
message => 'Unknown time parser', |
2892
|
|
|
|
|
|
|
default => 'Astro::App::Satpass2::ParseTime', |
2893
|
|
|
|
|
|
|
nocopy => 1, |
2894
|
|
|
|
|
|
|
prefix => [ 'Astro::App::Satpass2::ParseTime' ], |
2895
|
|
|
|
|
|
|
); |
2896
|
|
|
|
|
|
|
} |
2897
|
|
|
|
|
|
|
|
2898
|
|
|
|
|
|
|
sub _set_time_parser_attribute { |
2899
|
14
|
|
|
14
|
|
35
|
my ( $self, $name, $val ) = @_; |
2900
|
14
|
50
|
66
|
|
|
85
|
defined $val and $val eq 'undef' and $val = undef; |
2901
|
14
|
|
|
|
|
108
|
$self->{time_parser}->$name( $val ); |
2902
|
14
|
|
|
|
|
32
|
return $val; |
2903
|
|
|
|
|
|
|
} |
2904
|
|
|
|
|
|
|
|
2905
|
|
|
|
|
|
|
sub _set_time_parser_code { |
2906
|
0
|
|
|
0
|
|
0
|
my ( $code, $name ) = @_; |
2907
|
0
|
|
|
|
|
0
|
require Astro::App::Satpass2::ParseTime::Code; |
2908
|
0
|
|
|
|
|
0
|
my $obj = Astro::App::Satpass2::ParseTime::Code->new(); |
2909
|
0
|
|
|
|
|
0
|
return $obj->code( $code, $name ); |
2910
|
|
|
|
|
|
|
} |
2911
|
|
|
|
|
|
|
|
2912
|
|
|
|
|
|
|
_frame_pop_force_set ( 'twilight' ); # Force use of the set() method |
2913
|
|
|
|
|
|
|
# in _frame_pop(), because we |
2914
|
|
|
|
|
|
|
# need to set {_twilight} as |
2915
|
|
|
|
|
|
|
# well. |
2916
|
|
|
|
|
|
|
sub _set_twilight { |
2917
|
9
|
|
|
9
|
|
45
|
my ($self, $name, $val) = @_; |
2918
|
9
|
50
|
|
|
|
61
|
if (my $key = $twilight_abbr{lc $val}) { |
2919
|
9
|
|
|
|
|
46
|
$self->{$name} = $key; |
2920
|
9
|
|
|
|
|
30
|
$self->{_twilight} = $twilight_def{$key}; |
2921
|
|
|
|
|
|
|
} else { |
2922
|
0
|
|
|
|
|
0
|
my $angle = $self->__parse_angle( { accept => 1 }, $val ); |
2923
|
0
|
0
|
|
|
|
0
|
looks_like_number( $angle ) |
2924
|
|
|
|
|
|
|
or $self->wail( 'Twilight must be number or known keyword' ); |
2925
|
0
|
|
|
|
|
0
|
$self->{$name} = $val; |
2926
|
0
|
|
|
|
|
0
|
$self->{_twilight} = deg2rad ($angle); |
2927
|
|
|
|
|
|
|
} |
2928
|
9
|
|
|
|
|
30
|
return $val; |
2929
|
|
|
|
|
|
|
} |
2930
|
|
|
|
|
|
|
|
2931
|
|
|
|
|
|
|
sub _set_tz { |
2932
|
7
|
|
|
7
|
|
27
|
my ( $self, $name, $val ) = @_; |
2933
|
7
|
|
|
|
|
32
|
$self->_set_formatter_attribute( $name, $val ); |
2934
|
7
|
|
|
|
|
38
|
$self->_set_time_parser_attribute( $name, $val ); |
2935
|
7
|
|
|
|
|
21
|
return $val; |
2936
|
|
|
|
|
|
|
} |
2937
|
|
|
|
|
|
|
|
2938
|
|
|
|
|
|
|
sub _set_unmodified { |
2939
|
165
|
|
|
165
|
|
606
|
return ($_[0]{$_[1]} = $_[2]); |
2940
|
|
|
|
|
|
|
} |
2941
|
|
|
|
|
|
|
|
2942
|
|
|
|
|
|
|
sub _set_warner_attribute { |
2943
|
0
|
|
|
0
|
|
0
|
my ( $self, $name, $val ) = @_; |
2944
|
0
|
0
|
0
|
|
|
0
|
defined $val and $val eq 'undef' and $val = undef; |
2945
|
0
|
|
|
|
|
0
|
$self->{_warner}->$name( $val ); |
2946
|
0
|
|
|
|
|
0
|
return $val; |
2947
|
|
|
|
|
|
|
} |
2948
|
|
|
|
|
|
|
|
2949
|
|
|
|
|
|
|
sub _set_webcmd { |
2950
|
7
|
|
|
7
|
|
25
|
my ($self, $name, $val) = @_; |
2951
|
|
|
|
|
|
|
# TODO warn if $val is true but not '1'. |
2952
|
7
|
50
|
|
|
|
36
|
if ( my $st = $self->get( 'spacetrack' ) ) { |
2953
|
|
|
|
|
|
|
# TODO once spacetrack supports '1', just pass $val. |
2954
|
0
|
|
|
|
|
0
|
$st->set( webcmd => $self->_get_browser_command( $val ) ); |
2955
|
|
|
|
|
|
|
} |
2956
|
7
|
|
|
|
|
29
|
return ($self->{$name} = $val); |
2957
|
|
|
|
|
|
|
} |
2958
|
|
|
|
|
|
|
|
2959
|
|
|
|
|
|
|
sub show : Verb( changes! deprecated! readonly! ) { |
2960
|
23
|
|
|
23
|
1
|
126
|
my ( $self, $opt, @args ) = __arguments( @_ ); |
2961
|
|
|
|
|
|
|
|
2962
|
23
|
|
|
|
|
111
|
foreach my $name ( qw{ deprecated readonly } ) { |
2963
|
46
|
50
|
|
|
|
174
|
exists $opt->{$name} or $opt->{$name} = 1; |
2964
|
|
|
|
|
|
|
} |
2965
|
23
|
|
|
|
|
50
|
my $output; |
2966
|
|
|
|
|
|
|
|
2967
|
23
|
50
|
|
|
|
61
|
unless ( @args ) { |
2968
|
0
|
|
|
|
|
0
|
foreach my $name ( sort keys %accessor ) { |
2969
|
0
|
0
|
|
|
|
0
|
$self->_attribute_exists( $name, query => 1 ) |
2970
|
|
|
|
|
|
|
or next; |
2971
|
0
|
0
|
|
|
|
0
|
$nointeractive{$name} |
2972
|
|
|
|
|
|
|
and next; |
2973
|
|
|
|
|
|
|
exists $mutator{$name} |
2974
|
|
|
|
|
|
|
or $opt->{readonly} |
2975
|
0
|
0
|
0
|
|
|
0
|
or next; |
2976
|
0
|
|
|
|
|
0
|
my $depr; |
2977
|
|
|
|
|
|
|
( $depr = $self->_deprecation_in_progress( attribute => |
2978
|
|
|
|
|
|
|
$name ) ) |
2979
|
0
|
0
|
0
|
|
|
0
|
and ( not $opt->{deprecated} or $depr >= 3 ) |
|
|
|
0
|
|
|
|
|
2980
|
|
|
|
|
|
|
and next; |
2981
|
0
|
|
|
|
|
0
|
push @args, $name; |
2982
|
|
|
|
|
|
|
} |
2983
|
|
|
|
|
|
|
} |
2984
|
|
|
|
|
|
|
|
2985
|
23
|
|
|
|
|
51
|
foreach my $name (@args) { |
2986
|
23
|
50
|
|
|
|
92
|
exists $shower{$name} |
2987
|
|
|
|
|
|
|
or $self->wail("No such attribute as '$name'"); |
2988
|
|
|
|
|
|
|
|
2989
|
23
|
|
|
|
|
96
|
my @val = $shower{$name}->( $self, $name ); |
2990
|
23
|
50
|
|
|
|
74
|
if ( $opt->{changes} ) { |
2991
|
20
|
|
|
20
|
|
70812
|
no warnings qw{ uninitialized }; |
|
20
|
|
|
|
|
50
|
|
|
20
|
|
|
|
|
2897
|
|
2992
|
0
|
0
|
|
|
|
0
|
$static{$name} eq $val[-1] and next; |
2993
|
|
|
|
|
|
|
} |
2994
|
|
|
|
|
|
|
|
2995
|
23
|
50
|
|
|
|
67
|
exists $mutator{$name} or unshift @val, '#'; |
2996
|
23
|
|
|
|
|
79
|
$output .= quoter( @val ) . "\n"; |
2997
|
|
|
|
|
|
|
} |
2998
|
23
|
|
|
|
|
93
|
return $output; |
2999
|
20
|
|
|
20
|
|
175
|
} |
|
20
|
|
|
|
|
50
|
|
|
20
|
|
|
|
|
108
|
|
3000
|
|
|
|
|
|
|
|
3001
|
|
|
|
|
|
|
sub _show_copyable { |
3002
|
0
|
|
|
0
|
|
0
|
my ( $self, $name ) = @_; |
3003
|
0
|
|
|
|
|
0
|
my $obj = $self->get( $name ); |
3004
|
0
|
|
|
|
|
0
|
my $val = $obj->class_name_of_record(); |
3005
|
0
|
|
|
|
|
0
|
return ( 'set', $name, $val ); |
3006
|
|
|
|
|
|
|
} |
3007
|
|
|
|
|
|
|
|
3008
|
|
|
|
|
|
|
sub _show_formatter_attribute { |
3009
|
2
|
|
|
2
|
|
6
|
my ( $self, $name ) = @_; |
3010
|
2
|
|
|
|
|
9
|
my $val = $self->{formatter}->decode( $name ); |
3011
|
2
|
|
|
|
|
16
|
return ( qw{ formatter }, $name, $val ); |
3012
|
|
|
|
|
|
|
} |
3013
|
|
|
|
|
|
|
|
3014
|
|
|
|
|
|
|
sub _show_sun_class { |
3015
|
0
|
|
|
0
|
|
0
|
my ( $self, $name ) = @_; |
3016
|
0
|
|
|
|
|
0
|
$self->_attribute_exists( $name ); |
3017
|
0
|
|
|
|
|
0
|
return $self->_sky_class_components( $name ); |
3018
|
|
|
|
|
|
|
} |
3019
|
|
|
|
|
|
|
|
3020
|
|
|
|
|
|
|
sub _show_time_parser { |
3021
|
0
|
|
|
0
|
|
0
|
my ( $self, $name ) = @_; |
3022
|
0
|
|
|
|
|
0
|
my $obj = $self->get( $name ); |
3023
|
0
|
|
|
|
|
0
|
my $val = $obj->class_name_of_record(); |
3024
|
0
|
0
|
|
|
|
0
|
if ( my $back_end = $obj->back_end() ) { |
3025
|
0
|
|
|
|
|
0
|
$val = "$val,back_end=$back_end"; |
3026
|
|
|
|
|
|
|
} |
3027
|
0
|
|
|
|
|
0
|
return ( set => $name, $val ); |
3028
|
|
|
|
|
|
|
} |
3029
|
|
|
|
|
|
|
|
3030
|
|
|
|
|
|
|
sub _show_unmodified { |
3031
|
20
|
|
|
20
|
|
55
|
my ($self, $name) = @_; |
3032
|
20
|
|
|
|
|
61
|
my $val = $self->get( $name ); |
3033
|
20
|
|
|
|
|
97
|
return ( 'set', $name, $val ); |
3034
|
|
|
|
|
|
|
} |
3035
|
|
|
|
|
|
|
|
3036
|
|
|
|
|
|
|
# For proper motion, we need to convert arc seconds per year to degrees |
3037
|
|
|
|
|
|
|
# per second. Perl::Critic does not like 'use constant' because they do |
3038
|
|
|
|
|
|
|
# not interpolate, but they really do: "@{[SPY2DPS]}". |
3039
|
|
|
|
|
|
|
|
3040
|
20
|
|
|
20
|
|
10354
|
use constant SPY2DPS => 3600 * 365.24219 * SECSPERDAY; |
|
20
|
|
|
|
|
56
|
|
|
20
|
|
|
|
|
8369
|
|
3041
|
|
|
|
|
|
|
|
3042
|
|
|
|
|
|
|
# Given a body in the sky, encodes it in 'sky add' format |
3043
|
|
|
|
|
|
|
sub _sky_list_body { |
3044
|
8
|
|
|
8
|
|
16
|
my ( $body ) = @_; |
3045
|
8
|
50
|
|
|
|
31
|
if ( embodies( $body, 'Astro::Coord::ECI::TLE' ) ) { |
|
|
100
|
|
|
|
|
|
3046
|
0
|
|
|
|
|
0
|
return sprintf "sky tle %s\n", quoter( |
3047
|
|
|
|
|
|
|
$body->get( 'tle' ) ); |
3048
|
|
|
|
|
|
|
} elsif ( $body->isa( 'Astro::Coord::ECI::Star' ) ) { |
3049
|
1
|
|
|
|
|
76
|
my ( $ra, $dec, $rng, $pmra, $pmdec, $vr ) = $body->position(); |
3050
|
1
|
|
|
|
|
25
|
$rng /= PARSEC; |
3051
|
1
|
|
|
|
|
10
|
$pmra = rad2deg( $pmra / 24 * 360 * cos( $ra ) ) * SPY2DPS; |
3052
|
1
|
|
|
|
|
7
|
$pmdec = rad2deg( $pmdec ) * SPY2DPS; |
3053
|
1
|
|
|
|
|
6
|
return sprintf |
3054
|
|
|
|
|
|
|
"sky add %s %s %7.3f %.2f %.4f %.5f %s\n", |
3055
|
|
|
|
|
|
|
quoter( $body->get( 'name' ) ), _rad2hms( $ra ), |
3056
|
|
|
|
|
|
|
rad2deg( $dec ), $rng, $pmra, $pmdec, $vr; |
3057
|
|
|
|
|
|
|
} else { |
3058
|
7
|
|
|
|
|
229
|
return sprintf "sky add %s\n", quoter( $body->get( 'name' ) ); |
3059
|
|
|
|
|
|
|
} |
3060
|
|
|
|
|
|
|
} |
3061
|
|
|
|
|
|
|
|
3062
|
|
|
|
|
|
|
sub sky : Verb() Tweak( -completion _readline_complete_subcommand ) { |
3063
|
12
|
|
|
12
|
1
|
51
|
my ( $self, undef, @args ) = __arguments( @_ ); # $opt unused |
3064
|
|
|
|
|
|
|
|
3065
|
12
|
|
50
|
|
|
47
|
my $verb = lc ( shift @args || 'list' ); |
3066
|
|
|
|
|
|
|
|
3067
|
12
|
50
|
|
|
|
97
|
if ( my $code = $self->can( "_sky_sub_$verb") ) { |
3068
|
12
|
|
|
|
|
52
|
return $code->( $self, @args ); |
3069
|
|
|
|
|
|
|
} else { |
3070
|
0
|
|
|
|
|
0
|
$self->wail("'sky' subcommand '$verb' not known"); |
3071
|
|
|
|
|
|
|
} |
3072
|
0
|
|
|
|
|
0
|
return; # We can't get here, but Perl::Critic does not know this. |
3073
|
20
|
|
|
20
|
|
157
|
} |
|
20
|
|
|
|
|
50
|
|
|
20
|
|
|
|
|
121
|
|
3074
|
|
|
|
|
|
|
|
3075
|
|
|
|
|
|
|
# Given the name of a potential background object, return its |
3076
|
|
|
|
|
|
|
# definition. This is an array in list context, or a quoted string in |
3077
|
|
|
|
|
|
|
# scalar context. |
3078
|
|
|
|
|
|
|
sub _sky_class_components { |
3079
|
0
|
|
|
0
|
|
0
|
my ( $self, $name ) = @_; |
3080
|
0
|
0
|
|
|
|
0
|
my $info = $self->{sky_class}{ fold_case( $name ) } |
3081
|
|
|
|
|
|
|
or $self->weep( "No class defined for $name" ); |
3082
|
0
|
|
|
|
|
0
|
my ( $class, @attr ) = @{ $info }; |
|
0
|
|
|
|
|
0
|
|
3083
|
|
|
|
|
|
|
# We rely on sky( class => $name, $class, ... ) keeping the name |
3084
|
|
|
|
|
|
|
# last. |
3085
|
0
|
|
|
|
|
0
|
$name = pop @attr; |
3086
|
0
|
|
|
|
|
0
|
pop @attr; # 'name'; |
3087
|
0
|
|
|
|
|
0
|
my @parts = ( qw{ sky class }, $name, $class, @attr ); |
3088
|
|
|
|
|
|
|
wantarray |
3089
|
0
|
0
|
|
|
|
0
|
and return @parts; |
3090
|
0
|
|
|
|
|
0
|
return join ' ', map { quoter( $_ ) } @parts; |
|
0
|
|
|
|
|
0
|
|
3091
|
|
|
|
|
|
|
} |
3092
|
|
|
|
|
|
|
|
3093
|
|
|
|
|
|
|
# Given the name of a potential sky object, instantiate it. Named |
3094
|
|
|
|
|
|
|
# arguments are optional; the following are supported: |
3095
|
|
|
|
|
|
|
# fatal = Whether failure to find the name is fatal. Default is true. |
3096
|
|
|
|
|
|
|
sub _sky_object { |
3097
|
12
|
|
|
12
|
|
54
|
my ( $self, $name, %opt ) = @_; |
3098
|
|
|
|
|
|
|
defined $opt{fatal} |
3099
|
12
|
100
|
|
|
|
60
|
or $opt{fatal} = 1; |
3100
|
12
|
100
|
|
|
|
96
|
if ( my $info = $self->{sky_class}{ fold_case( $name ) } ) { |
|
|
50
|
|
|
|
|
|
3101
|
10
|
|
|
|
|
24
|
my ( $class, @attr ) = @{ $info }; |
|
10
|
|
|
|
|
88
|
|
3102
|
10
|
|
|
|
|
129
|
return $class->new( @attr ); |
3103
|
|
|
|
|
|
|
} elsif ( $opt{fatal} ) { |
3104
|
0
|
|
|
|
|
0
|
$self->weep( "No class defined for $name" ); |
3105
|
|
|
|
|
|
|
} |
3106
|
2
|
|
|
|
|
5
|
return; |
3107
|
|
|
|
|
|
|
} |
3108
|
|
|
|
|
|
|
|
3109
|
|
|
|
|
|
|
# Calls to the following _sky_sub_... methods are generated dynamically |
3110
|
|
|
|
|
|
|
# above, so there is no way Perl::Critic can find them. |
3111
|
|
|
|
|
|
|
# |
3112
|
|
|
|
|
|
|
sub _sky_sub_add : Verb() { ## no critic (ProhibitUnusedPrivateSubroutines) |
3113
|
5
|
|
|
5
|
|
20
|
my ( $self, undef, @args ) = __arguments( @_ ); # $opt unused |
3114
|
5
|
50
|
|
|
|
21
|
my $name = shift @args |
3115
|
|
|
|
|
|
|
or $self->wail( 'You did not specify what to add' ); |
3116
|
5
|
50
|
|
|
|
30
|
defined $self->_find_in_sky( $name ) |
3117
|
|
|
|
|
|
|
and return; |
3118
|
5
|
100
|
|
|
|
23
|
if ( my $obj = $self->_sky_object( $name, fatal => 0 ) ) { |
3119
|
3
|
|
|
|
|
266
|
push @{ $self->{sky} }, $obj; |
|
3
|
|
|
|
|
11
|
|
3120
|
|
|
|
|
|
|
} else { |
3121
|
2
|
100
|
|
|
|
24
|
@args >= 2 |
3122
|
|
|
|
|
|
|
or $self->wail( |
3123
|
|
|
|
|
|
|
'You must give at least right ascension and declination' ); |
3124
|
1
|
|
|
|
|
18
|
my $ra = deg2rad( $self->__parse_angle( shift @args ) ); |
3125
|
1
|
|
|
|
|
9
|
my $dec = deg2rad( $self->__parse_angle( shift @args ) ); |
3126
|
1
|
50
|
|
|
|
18
|
my $rng = @args ? |
3127
|
|
|
|
|
|
|
$self->__parse_distance( shift @args, '1pc' ) : |
3128
|
|
|
|
|
|
|
10000 * PARSEC; |
3129
|
1
|
50
|
|
|
|
9
|
my $pmra = @args ? do { |
3130
|
1
|
|
|
|
|
12
|
my $angle = shift @args; |
3131
|
1
|
50
|
|
|
|
18
|
$angle =~ s/ s \z //smxi |
3132
|
|
|
|
|
|
|
or $angle *= 24 / 360 / cos( $ra ); |
3133
|
1
|
|
|
|
|
24
|
deg2rad( $angle / SPY2DPS ); |
3134
|
|
|
|
|
|
|
} : 0; |
3135
|
1
|
50
|
|
|
|
15
|
my $pmdec = @args ? deg2rad( shift( @args ) / SPY2DPS ) : 0; |
3136
|
1
|
50
|
|
|
|
10
|
my $pmrec = @args ? shift @args : 0; |
3137
|
1
|
|
|
|
|
5
|
push @{ $self->{sky} }, Astro::Coord::ECI::Star->new( |
3138
|
|
|
|
|
|
|
debug => $self->{debug}, |
3139
|
1
|
|
|
|
|
4
|
name => $name, |
3140
|
|
|
|
|
|
|
sun => $self->_sky_object( 'sun' ), |
3141
|
|
|
|
|
|
|
)->position( $ra, $dec, $rng, $pmra, $pmdec, $pmrec ); |
3142
|
|
|
|
|
|
|
} |
3143
|
4
|
|
|
|
|
2116
|
return; |
3144
|
20
|
|
|
20
|
|
17009
|
} |
|
20
|
|
|
|
|
59
|
|
|
20
|
|
|
|
|
98
|
|
3145
|
|
|
|
|
|
|
|
3146
|
|
|
|
|
|
|
sub _sky_sub_class : Verb( add! delete! ) { ## no critic (ProhibitUnusedPrivateSubroutines) |
3147
|
0
|
|
|
0
|
|
0
|
my ( $self, $opt, @arg ) = __arguments( @_ ); |
3148
|
|
|
|
|
|
|
|
3149
|
|
|
|
|
|
|
$opt->{add} |
3150
|
|
|
|
|
|
|
and $opt->{delete} |
3151
|
0
|
0
|
0
|
|
|
0
|
and $self->wail( 'May not specify both add and delete' ); |
3152
|
|
|
|
|
|
|
|
3153
|
0
|
0
|
|
|
|
0
|
if ( $opt->{delete} ) { |
|
|
0
|
|
|
|
|
|
3154
|
0
|
|
|
|
|
0
|
foreach my $name ( @arg ) { |
3155
|
0
|
0
|
|
|
|
0
|
$name =~ m/ \A sun \z /smxi |
3156
|
|
|
|
|
|
|
and $self->wail( 'Can not remove Sun class' ); |
3157
|
0
|
0
|
|
|
|
0
|
defined $self->_find_in_sky( $name ) |
3158
|
|
|
|
|
|
|
and $self->wail( 'Can not remove in-use class' ); |
3159
|
0
|
|
|
|
|
0
|
delete $self->{sky_class}{ fold_case( $name ) }; |
3160
|
|
|
|
|
|
|
} |
3161
|
|
|
|
|
|
|
} elsif ( @arg < 2 ) { |
3162
|
|
|
|
|
|
|
@arg |
3163
|
0
|
0
|
|
|
|
0
|
or @arg = sort keys %{ $self->{sky_class} }; |
|
0
|
|
|
|
|
0
|
|
3164
|
|
|
|
|
|
|
return join '', map { |
3165
|
0
|
|
|
|
|
0
|
$self->_sky_class_components( $_ ) . "\n" } |
|
0
|
|
|
|
|
0
|
|
3166
|
|
|
|
|
|
|
@arg; |
3167
|
|
|
|
|
|
|
} else { |
3168
|
0
|
|
|
|
|
0
|
my ( $name, $class, @attr ) = @arg; |
3169
|
0
|
|
|
|
|
0
|
$self->load_package( { fatal => 'wail' }, $class ); |
3170
|
0
|
0
|
|
|
|
0
|
my $want_class = $name =~ m/ \A sun \z /smxi ? |
3171
|
|
|
|
|
|
|
SUN_CLASS_DEFAULT : |
3172
|
|
|
|
|
|
|
'Astro::Coord::ECI'; |
3173
|
0
|
0
|
|
|
|
0
|
embodies( $class, $want_class ) |
3174
|
|
|
|
|
|
|
or $self->wail( |
3175
|
|
|
|
|
|
|
"Must be a subclass of $want_class" ); |
3176
|
|
|
|
|
|
|
+{ @attr }->{name} |
3177
|
0
|
0
|
|
|
|
0
|
and $self->wail( 'May not specify name explicitly' ); |
3178
|
|
|
|
|
|
|
# name must be last, because _sky_class_components() |
3179
|
|
|
|
|
|
|
# needs to recover it. |
3180
|
0
|
|
|
|
|
0
|
push @attr, name => $name; |
3181
|
0
|
|
|
|
|
0
|
my $obj = $class->new( @attr ); |
3182
|
0
|
|
|
|
|
0
|
my $folded_name = fold_case( $name ); |
3183
|
0
|
|
|
|
|
0
|
$self->{sky_class}{$folded_name} = [ $class, @attr ]; |
3184
|
|
|
|
|
|
|
$self->_replace_in_sky( $folded_name, $obj ) |
3185
|
|
|
|
|
|
|
or $opt->{add} |
3186
|
0
|
0
|
0
|
|
|
0
|
and push @{ $self->{sky} }, $obj; |
|
0
|
|
|
|
|
0
|
|
3187
|
0
|
|
|
|
|
0
|
$self->{_help_module}{$folded_name} = $class; |
3188
|
0
|
0
|
|
|
|
0
|
if ( $obj->isa( 'Astro::Coord::ECI::Sun' ) ) { |
3189
|
0
|
|
|
|
|
0
|
foreach my $body ( |
3190
|
0
|
|
|
|
|
0
|
@{ $self->{bodies} }, @{ $self->{sky} } |
|
0
|
|
|
|
|
0
|
|
3191
|
|
|
|
|
|
|
) { |
3192
|
0
|
|
|
|
|
0
|
$body->set( |
3193
|
|
|
|
|
|
|
sun => $self->_sky_object( 'sun' ), |
3194
|
|
|
|
|
|
|
); |
3195
|
|
|
|
|
|
|
} |
3196
|
|
|
|
|
|
|
} |
3197
|
|
|
|
|
|
|
} |
3198
|
|
|
|
|
|
|
|
3199
|
0
|
|
|
|
|
0
|
return; |
3200
|
20
|
|
|
20
|
|
13249
|
} |
|
20
|
|
|
|
|
57
|
|
|
20
|
|
|
|
|
105
|
|
3201
|
|
|
|
|
|
|
|
3202
|
|
|
|
|
|
|
sub _sky_sub_clear : Verb() { ## no critic (ProhibitUnusedPrivateSubroutines) |
3203
|
1
|
|
|
1
|
|
5
|
my ( $self ) = __arguments( @_ ); # $opt and args unused |
3204
|
1
|
|
|
|
|
7
|
@{ $self->{sky} } = (); |
|
1
|
|
|
|
|
3
|
|
3205
|
1
|
|
|
|
|
4
|
return; |
3206
|
20
|
|
|
20
|
|
4987
|
} |
|
20
|
|
|
|
|
54
|
|
|
20
|
|
|
|
|
92
|
|
3207
|
|
|
|
|
|
|
|
3208
|
|
|
|
|
|
|
sub _sky_sub_drop : Verb() Tweak( -completion _sky_body_complete ) { ## no critic (ProhibitUnusedPrivateSubroutines) |
3209
|
1
|
|
|
1
|
|
11
|
my ( $self, undef, @args ) = __arguments( @_ ); # $opt unused |
3210
|
1
|
50
|
|
|
|
35
|
@args or $self->wail( |
3211
|
|
|
|
|
|
|
'You must specify at least one name to drop' ); |
3212
|
1
|
|
|
|
|
19
|
foreach my $name ( @args ) { |
3213
|
1
|
|
|
|
|
8
|
$self->_drop_from_sky( $name ); |
3214
|
|
|
|
|
|
|
} |
3215
|
1
|
|
|
|
|
13
|
return; |
3216
|
20
|
|
|
20
|
|
5630
|
} |
|
20
|
|
|
|
|
51
|
|
|
20
|
|
|
|
|
102
|
|
3217
|
|
|
|
|
|
|
|
3218
|
|
|
|
|
|
|
sub _sky_sub_list : Verb( verbose! ) { ## no critic (ProhibitUnusedPrivateSubroutines) |
3219
|
5
|
|
|
5
|
|
22
|
my ( $self, $opt ) = __arguments( @_ ); # args unused |
3220
|
5
|
|
|
|
|
17
|
my $output; |
3221
|
5
|
|
|
|
|
16
|
foreach my $body ( |
3222
|
8
|
|
|
|
|
47
|
map { $_->[1] } |
3223
|
4
|
|
|
|
|
76
|
sort { $a->[0] cmp $b->[0] } |
3224
|
8
|
|
33
|
|
|
140
|
map { [ lc( $_->get( 'name' ) || $_->get( 'id' ) ), $_ ] } |
3225
|
5
|
|
|
|
|
21
|
@{$self->{sky}} |
3226
|
|
|
|
|
|
|
) { |
3227
|
8
|
|
|
|
|
24
|
$output .= _sky_list_body( $body ); |
3228
|
8
|
50
|
|
|
|
51
|
if ( $opt->{verbose} ) { |
3229
|
0
|
|
|
|
|
0
|
$output .= "# Class: @{[ ref $body ]}\n"; |
|
0
|
|
|
|
|
0
|
|
3230
|
|
|
|
|
|
|
} |
3231
|
|
|
|
|
|
|
} |
3232
|
5
|
100
|
|
|
|
17
|
unless (@{$self->{sky}}) { |
|
5
|
|
|
|
|
24
|
|
3233
|
|
|
|
|
|
|
$self->{warn_on_empty} |
3234
|
1
|
50
|
|
|
|
5
|
and $self->whinge( 'The sky is empty' ); |
3235
|
|
|
|
|
|
|
} |
3236
|
5
|
|
|
|
|
23
|
return $output; |
3237
|
20
|
|
|
20
|
|
8667
|
} |
|
20
|
|
|
|
|
82
|
|
|
20
|
|
|
|
|
116
|
|
3238
|
|
|
|
|
|
|
|
3239
|
|
|
|
|
|
|
# Undocumented. That means I can revoke at any time, without notice. If |
3240
|
|
|
|
|
|
|
# you need this functionality, please contact me. |
3241
|
|
|
|
|
|
|
sub _sky_sub_load : Verb() { ## no critic (ProhibitUnusedPrivateSubroutines) |
3242
|
0
|
|
|
0
|
|
0
|
my ( $self, undef, @args ) = __arguments( @_ ); # $opt unused |
3243
|
0
|
|
|
|
|
0
|
my $tle; |
3244
|
0
|
|
|
|
|
0
|
foreach my $fn ( @args ) { |
3245
|
0
|
|
|
|
|
0
|
local $/ = undef; |
3246
|
0
|
0
|
|
|
|
0
|
open my $fh, '<', $fn |
3247
|
|
|
|
|
|
|
or $self->wail( "Failed to open $fn: $!" ); |
3248
|
0
|
|
|
|
|
0
|
$tle .= <$fh>; |
3249
|
0
|
|
|
|
|
0
|
close $fh; |
3250
|
|
|
|
|
|
|
} |
3251
|
0
|
|
|
|
|
0
|
return $self->_sky_sub_tle( $tle ); |
3252
|
20
|
|
|
20
|
|
6444
|
} |
|
20
|
|
|
|
|
54
|
|
|
20
|
|
|
|
|
98
|
|
3253
|
|
|
|
|
|
|
|
3254
|
|
|
|
|
|
|
sub _sky_sub_lookup : Verb() { ## no critic (ProhibitUnusedPrivateSubroutines) |
3255
|
0
|
|
|
0
|
|
0
|
my ( $self, undef, @args ) = __arguments( @_ ); # $opt unused |
3256
|
0
|
|
|
|
|
0
|
my $output; |
3257
|
0
|
|
|
|
|
0
|
my $name = shift @args; |
3258
|
0
|
0
|
|
|
|
0
|
defined $self->_find_in_sky( $name ) |
3259
|
|
|
|
|
|
|
and $self->wail( "Duplicate sky entry '$name'" ); |
3260
|
0
|
|
|
|
|
0
|
my ($ra, $dec, $rng, $pmra, $pmdec, $pmrec) = |
3261
|
|
|
|
|
|
|
$self->_simbad4 ($name); |
3262
|
0
|
|
|
|
|
0
|
$rng = sprintf '%.2f', $rng; |
3263
|
0
|
|
|
|
|
0
|
$output .= 'sky add ' . quoter ($name) . |
3264
|
|
|
|
|
|
|
" $ra $dec $rng $pmra $pmdec $pmrec\n"; |
3265
|
0
|
|
|
|
|
0
|
$ra = deg2rad ($self->__parse_angle ($ra)); |
3266
|
0
|
|
|
|
|
0
|
my $body = Astro::Coord::ECI::Star->new( |
3267
|
|
|
|
|
|
|
name => $name, |
3268
|
|
|
|
|
|
|
sun => $self->_sky_object( 'sun' ), |
3269
|
|
|
|
|
|
|
); |
3270
|
0
|
|
|
|
|
0
|
$body->position ($ra, deg2rad ($self->__parse_angle ($dec)), |
3271
|
|
|
|
|
|
|
$rng * PARSEC, deg2rad ($pmra * 24 / 360 / cos ($ra) / SPY2DPS), |
3272
|
|
|
|
|
|
|
deg2rad ($pmdec / SPY2DPS), $pmrec); |
3273
|
0
|
|
|
|
|
0
|
push @{$self->{sky}}, $body; |
|
0
|
|
|
|
|
0
|
|
3274
|
0
|
|
|
|
|
0
|
return $output; |
3275
|
20
|
|
|
20
|
|
8771
|
} |
|
20
|
|
|
|
|
59
|
|
|
20
|
|
|
|
|
114
|
|
3276
|
|
|
|
|
|
|
|
3277
|
|
|
|
|
|
|
# Undocumented. That means I can revoke at any time, without notice. If |
3278
|
|
|
|
|
|
|
# you need this functionality, please contact me. |
3279
|
|
|
|
|
|
|
sub _sky_sub_tle : Verb() { |
3280
|
0
|
|
|
0
|
|
0
|
my ( $self, undef, $tle ) = __arguments( @_ ); # $opt unused |
3281
|
0
|
|
|
|
|
0
|
my @bodies = Astro::Coord::ECI::TLE::Set->aggregate( |
3282
|
|
|
|
|
|
|
Astro::Coord::ECI::TLE->parse( $tle ) ); |
3283
|
0
|
|
|
|
|
0
|
my %extant = map { $_->get( 'id' ) => 1 } |
3284
|
0
|
|
|
|
|
0
|
grep { embodies( $_, 'Astro::Coord::ECI::TLE' ) } |
3285
|
0
|
|
|
|
|
0
|
@{ $self->{sky} }; |
|
0
|
|
|
|
|
0
|
|
3286
|
0
|
|
|
|
|
0
|
foreach my $body ( @bodies ) { |
3287
|
0
|
|
|
|
|
0
|
my $id = $body->get( 'id' ); |
3288
|
0
|
0
|
|
|
|
0
|
$extant{$id} |
3289
|
|
|
|
|
|
|
and $self->wail( "Duplicate sky entry $id" ); |
3290
|
|
|
|
|
|
|
} |
3291
|
0
|
|
|
|
|
0
|
push @{ $self->{sky} }, @bodies; |
|
0
|
|
|
|
|
0
|
|
3292
|
0
|
|
|
|
|
0
|
return sprintf "sky tle %s\n", quoter( $tle ); |
3293
|
20
|
|
|
20
|
|
7954
|
} |
|
20
|
|
|
|
|
85
|
|
|
20
|
|
|
|
|
107
|
|
3294
|
|
|
|
|
|
|
|
3295
|
|
|
|
|
|
|
sub source : Verb( optional! ) { |
3296
|
8
|
|
|
8
|
1
|
42
|
my ( $self, $opt, $src, @args ) = __arguments( @_ ); |
3297
|
|
|
|
|
|
|
|
3298
|
8
|
|
|
|
|
25
|
my $output; |
3299
|
8
|
100
|
|
|
|
31
|
my $reader = $self->_file_reader( $src, $opt ) |
3300
|
|
|
|
|
|
|
or return; |
3301
|
|
|
|
|
|
|
|
3302
|
6
|
|
|
|
|
14
|
my @level1_cache; |
3303
|
6
|
|
|
|
|
12
|
my $level1_context = {}; |
3304
|
|
|
|
|
|
|
my $fetcher = $opt->{level1} ? sub { |
3305
|
|
|
|
|
|
|
@level1_cache |
3306
|
21
|
100
|
|
21
|
|
52
|
and return shift @level1_cache; |
3307
|
19
|
|
|
|
|
36
|
my $buffer = $reader->(); |
3308
|
19
|
|
|
|
|
68
|
@level1_cache = $self->_rewrite_level1_command( |
3309
|
|
|
|
|
|
|
$buffer, $level1_context ); |
3310
|
19
|
|
|
|
|
60
|
return shift @level1_cache; |
3311
|
6
|
100
|
|
|
|
30
|
} : $reader; |
3312
|
|
|
|
|
|
|
|
3313
|
6
|
|
|
|
|
33
|
my $frames = $self->_frame_push( source => \@args ); |
3314
|
|
|
|
|
|
|
# Note that level1 is unsupported, and works only when the |
3315
|
|
|
|
|
|
|
# options are passed as a hash. It will go away when support for |
3316
|
|
|
|
|
|
|
# the original satpass script is dropped. |
3317
|
6
|
|
|
|
|
32
|
$self->{frame}[-1]{level1} = $opt->{level1}; |
3318
|
6
|
|
|
|
|
12
|
my $err; |
3319
|
6
|
50
|
|
|
|
21
|
my $ok = eval { while ( defined( my $input = $fetcher->() ) ) { |
|
6
|
|
|
|
|
15
|
|
3320
|
13
|
100
|
|
|
|
70
|
if ( defined ( my $buffer = $self->execute( $fetcher, |
3321
|
|
|
|
|
|
|
$input ) ) ) { |
3322
|
2
|
|
|
|
|
25
|
$output .= $buffer; |
3323
|
|
|
|
|
|
|
} |
3324
|
|
|
|
|
|
|
} |
3325
|
6
|
|
|
|
|
27
|
1; |
3326
|
|
|
|
|
|
|
} or $err = $@; |
3327
|
|
|
|
|
|
|
|
3328
|
6
|
|
|
|
|
27
|
$self->_frame_pop( $frames ); |
3329
|
6
|
50
|
|
|
|
16
|
$ok or $self->whinge( $err ); |
3330
|
|
|
|
|
|
|
|
3331
|
6
|
100
|
|
|
|
23
|
$opt->{level1} and $self->_rewrite_level1_macros(); |
3332
|
6
|
|
|
|
|
112
|
return $output; |
3333
|
20
|
|
|
20
|
|
9356
|
} |
|
20
|
|
|
|
|
47
|
|
|
20
|
|
|
|
|
99
|
|
3334
|
|
|
|
|
|
|
|
3335
|
|
|
|
|
|
|
{ |
3336
|
|
|
|
|
|
|
|
3337
|
|
|
|
|
|
|
my %handler = ( |
3338
|
|
|
|
|
|
|
config => sub { |
3339
|
|
|
|
|
|
|
my ( $self, $obj, undef, $opt, @args ) = @_; # $method unused |
3340
|
|
|
|
|
|
|
@args or @args = $obj->attribute_names(); |
3341
|
|
|
|
|
|
|
my ( $rslt, @values, $virgin ); |
3342
|
|
|
|
|
|
|
$opt->{changes} |
3343
|
|
|
|
|
|
|
and $virgin = $self->_get_spacetrack_default(); |
3344
|
|
|
|
|
|
|
foreach my $name ( @args ) { |
3345
|
|
|
|
|
|
|
$rslt = $obj->get( $name ); |
3346
|
|
|
|
|
|
|
$rslt->is_success() |
3347
|
|
|
|
|
|
|
or return $rslt; |
3348
|
|
|
|
|
|
|
my $value = $rslt->content(); |
3349
|
20
|
|
|
20
|
|
5812
|
no warnings qw{ uninitialized }; |
|
20
|
|
|
|
|
59
|
|
|
20
|
|
|
|
|
16080
|
|
3350
|
|
|
|
|
|
|
$opt->{changes} |
3351
|
|
|
|
|
|
|
and $value eq $virgin->getv( $name ) |
3352
|
|
|
|
|
|
|
and next; |
3353
|
|
|
|
|
|
|
push @values, [ $name, $value ]; |
3354
|
|
|
|
|
|
|
} |
3355
|
|
|
|
|
|
|
if ( $opt->{raw} ) { |
3356
|
|
|
|
|
|
|
$rslt->content( \@values ); |
3357
|
|
|
|
|
|
|
} else { |
3358
|
|
|
|
|
|
|
$opt->{raw} and return \@values; |
3359
|
|
|
|
|
|
|
my $output = ''; |
3360
|
|
|
|
|
|
|
foreach ( @values ) { |
3361
|
|
|
|
|
|
|
$output .= quoter( qw{ spacetrack set }, @{ $_ } ) . "\n"; |
3362
|
|
|
|
|
|
|
} |
3363
|
|
|
|
|
|
|
$rslt->content( $output ); |
3364
|
|
|
|
|
|
|
} |
3365
|
|
|
|
|
|
|
return $rslt; |
3366
|
|
|
|
|
|
|
}, |
3367
|
|
|
|
|
|
|
get => sub { |
3368
|
|
|
|
|
|
|
my ( undef, $obj, undef, $opt, @args ) = @_; # Invocant, $method unused |
3369
|
|
|
|
|
|
|
my $rslt = $obj->get( @args ); |
3370
|
|
|
|
|
|
|
$rslt->is_success |
3371
|
|
|
|
|
|
|
and not $opt->{raw} |
3372
|
|
|
|
|
|
|
and $rslt->content( scalar quoter( |
3373
|
|
|
|
|
|
|
qw{ spacetrack set }, $args[0], $rslt->content() ) ); |
3374
|
|
|
|
|
|
|
return $rslt; |
3375
|
|
|
|
|
|
|
}, |
3376
|
|
|
|
|
|
|
set => sub { |
3377
|
|
|
|
|
|
|
my ( undef, $obj, $method, undef, @args ) = @_; # Invocant, $opt unused |
3378
|
|
|
|
|
|
|
return $obj->$method( @args ); |
3379
|
|
|
|
|
|
|
}, |
3380
|
|
|
|
|
|
|
); |
3381
|
|
|
|
|
|
|
$handler{getv} = $handler{get}; |
3382
|
|
|
|
|
|
|
$handler{show} = $handler{config}; |
3383
|
|
|
|
|
|
|
$handler{spacetrack_query_v2} = $handler{set}; |
3384
|
|
|
|
|
|
|
|
3385
|
|
|
|
|
|
|
my %suppress_output = map { $_ => 1 } '', 'set'; |
3386
|
|
|
|
|
|
|
|
3387
|
|
|
|
|
|
|
# Attributes must all be on one line to process correctly under |
3388
|
|
|
|
|
|
|
# 5.8.8. |
3389
|
|
|
|
|
|
|
sub spacetrack : Verb( all! changes! descending! effective! end_epoch=s exclude=s last5! raw! rcs! status=s sort=s start_epoch=s tle! verbose! ) { |
3390
|
0
|
|
|
0
|
1
|
0
|
my ( $self, $opt, $method, @args ) = __arguments( @_ ); |
3391
|
|
|
|
|
|
|
|
3392
|
|
|
|
|
|
|
exists $opt->{raw} |
3393
|
0
|
0
|
|
|
|
0
|
or $opt->{raw} = ( ! _is_interactive() ); |
3394
|
|
|
|
|
|
|
|
3395
|
0
|
|
|
|
|
0
|
my $verbose = delete $opt->{verbose}; |
3396
|
|
|
|
|
|
|
|
3397
|
0
|
|
|
|
|
0
|
my $object = $self->_helper_get_object( 'spacetrack' ); |
3398
|
|
|
|
|
|
|
$method !~ m/ \A _ /smx and $object->can( $method ) |
3399
|
0
|
0
|
0
|
|
|
0
|
or $handler{$method} |
|
|
|
0
|
|
|
|
|
3400
|
|
|
|
|
|
|
or $self->wail("No such spacetrack method as '$method'"); |
3401
|
|
|
|
|
|
|
|
3402
|
|
|
|
|
|
|
$opt->{start_epoch} |
3403
|
|
|
|
|
|
|
and $opt->{start_epoch} = $self->__parse_time( |
3404
|
0
|
0
|
|
|
|
0
|
$opt->{start_epoch} ); |
3405
|
|
|
|
|
|
|
$opt->{end_epoch} |
3406
|
|
|
|
|
|
|
and $opt->{end_epoch} = $self->__parse_time( |
3407
|
0
|
0
|
|
|
|
0
|
$opt->{end_epoch} ); |
3408
|
|
|
|
|
|
|
|
3409
|
0
|
|
|
|
|
0
|
my ( $rslt, @rest ); |
3410
|
0
|
0
|
|
|
|
0
|
if ( $handler{$method} ) { |
3411
|
0
|
|
|
|
|
0
|
( $rslt, @rest ) = $handler{$method}->( |
3412
|
|
|
|
|
|
|
$self, $object, $method, $opt, @args ); |
3413
|
|
|
|
|
|
|
} else { |
3414
|
0
|
|
|
|
|
0
|
delete $opt->{raw}; |
3415
|
0
|
|
|
|
|
0
|
( $rslt, @rest ) = $object->$method( $opt, @args ); |
3416
|
|
|
|
|
|
|
} |
3417
|
|
|
|
|
|
|
|
3418
|
0
|
0
|
|
|
|
0
|
$rslt->is_success() |
3419
|
|
|
|
|
|
|
or $self->wail( $rslt->status_line() ); |
3420
|
|
|
|
|
|
|
|
3421
|
0
|
|
|
|
|
0
|
my $output; |
3422
|
0
|
|
0
|
|
|
0
|
my $content_type = $object->content_type || ''; |
3423
|
|
|
|
|
|
|
|
3424
|
0
|
0
|
0
|
|
|
0
|
if ($content_type eq 'orbit') { |
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
3425
|
|
|
|
|
|
|
|
3426
|
0
|
|
|
|
|
0
|
push @{$self->{bodies}}, |
|
0
|
|
|
|
|
0
|
|
3427
|
|
|
|
|
|
|
Astro::Coord::ECI::TLE->parse ($rslt->content); |
3428
|
0
|
0
|
|
|
|
0
|
$verbose |
3429
|
|
|
|
|
|
|
and $output .= $rslt->content; |
3430
|
|
|
|
|
|
|
|
3431
|
|
|
|
|
|
|
} elsif ($content_type eq 'iridium-status') { |
3432
|
|
|
|
|
|
|
|
3433
|
0
|
|
|
|
|
0
|
$self->_iridium_status( @rest ); |
3434
|
0
|
0
|
|
|
|
0
|
$verbose |
3435
|
|
|
|
|
|
|
and $output .= $rslt->content; |
3436
|
|
|
|
|
|
|
|
3437
|
|
|
|
|
|
|
} elsif ( ! $suppress_output{$content_type} || $verbose ) { |
3438
|
|
|
|
|
|
|
|
3439
|
0
|
|
|
|
|
0
|
$output .= $rslt->content; |
3440
|
|
|
|
|
|
|
|
3441
|
|
|
|
|
|
|
} |
3442
|
|
|
|
|
|
|
|
3443
|
0
|
0
|
|
|
|
0
|
defined $output |
3444
|
|
|
|
|
|
|
and $output =~ s/ (?
|
3445
|
0
|
|
|
|
|
0
|
return $output; |
3446
|
20
|
|
|
20
|
|
182
|
} |
|
20
|
|
|
|
|
51
|
|
|
20
|
|
|
|
|
93
|
|
3447
|
|
|
|
|
|
|
|
3448
|
|
|
|
|
|
|
} |
3449
|
|
|
|
|
|
|
|
3450
|
|
|
|
|
|
|
sub st : Verb() { |
3451
|
0
|
|
|
0
|
1
|
0
|
my ( $self, undef, $func, @args ) = __arguments( @_ ); # $opt unused |
3452
|
|
|
|
|
|
|
|
3453
|
0
|
|
|
|
|
0
|
$self->_deprecation_notice( method => 'st' ); |
3454
|
0
|
0
|
|
|
|
0
|
if ( 'localize' eq $func ) { |
3455
|
0
|
|
|
|
|
0
|
my $st = $self->_helper_get_object( 'spacetrack' ); |
3456
|
0
|
|
|
|
|
0
|
foreach my $key (@args) { |
3457
|
|
|
|
|
|
|
exists $self->{frame}[-1]{spacetrack}{$key} |
3458
|
0
|
0
|
|
|
|
0
|
or $self->{frame}[-1]{spacetrack}{$key} = |
3459
|
|
|
|
|
|
|
$st->get ($key)->content |
3460
|
|
|
|
|
|
|
} |
3461
|
|
|
|
|
|
|
} else { |
3462
|
0
|
|
|
|
|
0
|
goto &spacetrack; |
3463
|
|
|
|
|
|
|
} |
3464
|
0
|
|
|
|
|
0
|
return; |
3465
|
20
|
|
|
20
|
|
7199
|
} |
|
20
|
|
|
|
|
61
|
|
|
20
|
|
|
|
|
106
|
|
3466
|
|
|
|
|
|
|
|
3467
|
|
|
|
|
|
|
sub station { |
3468
|
34
|
|
|
34
|
1
|
110
|
my ( $self ) = @_; |
3469
|
|
|
|
|
|
|
|
3470
|
|
|
|
|
|
|
defined $self->{height} |
3471
|
|
|
|
|
|
|
and defined $self->{latitude} |
3472
|
|
|
|
|
|
|
and defined $self->{longitude} |
3473
|
34
|
50
|
33
|
|
|
359
|
or $self->wail( 'You must set height, latitude, and longitude' ); |
|
|
|
33
|
|
|
|
|
3474
|
|
|
|
|
|
|
|
3475
|
|
|
|
|
|
|
return Astro::Coord::ECI->new ( |
3476
|
|
|
|
|
|
|
almanac_horizon => $self->{_almanac_horizon}, |
3477
|
|
|
|
|
|
|
horizon => deg2rad( $self->get( 'horizon' ) ), |
3478
|
|
|
|
|
|
|
id => 'station', |
3479
|
|
|
|
|
|
|
name => $self->{location} || '', |
3480
|
|
|
|
|
|
|
refraction => $self->{refraction} || 0, |
3481
|
|
|
|
|
|
|
)->geodetic ( |
3482
|
|
|
|
|
|
|
deg2rad( $self->{latitude} ), |
3483
|
|
|
|
|
|
|
deg2rad( $self->{longitude} ), |
3484
|
34
|
|
100
|
|
|
143
|
$self->{height} / 1000 |
|
|
|
50
|
|
|
|
|
3485
|
|
|
|
|
|
|
); |
3486
|
|
|
|
|
|
|
} |
3487
|
|
|
|
|
|
|
|
3488
|
|
|
|
|
|
|
# TODO I must have thought -reload would be good for something, but it |
3489
|
|
|
|
|
|
|
# appears I never implemented it. |
3490
|
|
|
|
|
|
|
|
3491
|
|
|
|
|
|
|
sub status : Verb( name! reload! ) { |
3492
|
3
|
|
|
3
|
1
|
18
|
my ( $self, $opt, @args ) = __arguments( @_ ); |
3493
|
|
|
|
|
|
|
|
3494
|
3
|
100
|
|
|
|
34
|
@args or @args = qw{show}; |
3495
|
|
|
|
|
|
|
|
3496
|
3
|
|
50
|
|
|
20
|
my $verb = lc (shift (@args) || 'show'); |
3497
|
|
|
|
|
|
|
|
3498
|
3
|
50
|
|
|
|
15
|
if ( $verb eq 'iridium' ) { |
3499
|
0
|
|
|
|
|
0
|
$self->_deprecation_notice( status => 'iridium', 'show' ); |
3500
|
0
|
|
|
|
|
0
|
$verb = 'show'; |
3501
|
|
|
|
|
|
|
} |
3502
|
|
|
|
|
|
|
|
3503
|
3
|
|
|
|
|
8
|
my $output; |
3504
|
|
|
|
|
|
|
|
3505
|
3
|
100
|
66
|
|
|
55
|
if ($verb eq 'add' || $verb eq 'drop') { |
|
|
100
|
33
|
|
|
|
|
|
|
50
|
|
|
|
|
|
3506
|
|
|
|
|
|
|
|
3507
|
1
|
|
|
|
|
19
|
Astro::Coord::ECI::TLE->status ($verb, @args); |
3508
|
1
|
|
|
|
|
15
|
foreach my $tle (@{$self->{bodies}}) { |
|
1
|
|
|
|
|
10
|
|
3509
|
1
|
50
|
|
|
|
7
|
$tle->get ('id') == $args[0] and $tle->rebless (); |
3510
|
|
|
|
|
|
|
} |
3511
|
|
|
|
|
|
|
|
3512
|
|
|
|
|
|
|
} elsif ($verb eq 'clear') { |
3513
|
|
|
|
|
|
|
|
3514
|
1
|
|
|
|
|
21
|
Astro::Coord::ECI::TLE->status ($verb, @args); |
3515
|
1
|
|
|
|
|
22
|
foreach my $tle (@{$self->{bodies}}) { |
|
1
|
|
|
|
|
9
|
|
3516
|
2
|
|
|
|
|
135
|
$tle->rebless (); |
3517
|
|
|
|
|
|
|
} |
3518
|
|
|
|
|
|
|
|
3519
|
|
|
|
|
|
|
} elsif ($verb eq 'show' || $verb eq 'list') { |
3520
|
|
|
|
|
|
|
|
3521
|
1
|
|
|
|
|
7
|
my @data = Astro::Coord::ECI::TLE->status( 'show', @args ); |
3522
|
1
|
50
|
|
|
|
20
|
@data = sort {$a->[3] cmp $b->[3]} @data if $opt->{name}; |
|
0
|
|
|
|
|
0
|
|
3523
|
1
|
|
|
|
|
3
|
$output .= ''; # Don't want it to be undef. |
3524
|
|
|
|
|
|
|
|
3525
|
|
|
|
|
|
|
my $encoder = ( HAVE_TLE_IRIDIUM && |
3526
|
|
|
|
|
|
|
Astro::Coord::ECI::TLE::Iridium->can( |
3527
|
1
|
|
|
0
|
|
12
|
'__encode_operational_status' ) ) || sub { return $_[2] }; |
|
0
|
|
|
|
|
0
|
|
3528
|
|
|
|
|
|
|
|
3529
|
1
|
|
|
|
|
7
|
foreach my $tle (@data) { |
3530
|
0
|
|
|
|
|
0
|
my $status = $encoder->( undef, status => $tle->[2] ); |
3531
|
0
|
|
|
|
|
0
|
$output .= quoter( 'status', 'add', |
3532
|
|
|
|
|
|
|
$tle->[0], $tle->[1], $status, |
3533
|
|
|
|
|
|
|
$tle->[3], $tle->[4] ) . "\n"; |
3534
|
|
|
|
|
|
|
} |
3535
|
|
|
|
|
|
|
|
3536
|
|
|
|
|
|
|
} else { |
3537
|
0
|
|
|
|
|
0
|
$output .= ''; # Don't want it to be undef. |
3538
|
0
|
|
|
|
|
0
|
$output .= Astro::Coord::ECI::TLE->status ($verb, @args); |
3539
|
|
|
|
|
|
|
} |
3540
|
|
|
|
|
|
|
|
3541
|
3
|
|
|
|
|
229
|
return $output; |
3542
|
|
|
|
|
|
|
|
3543
|
20
|
|
|
20
|
|
14665
|
} |
|
20
|
|
|
|
|
77
|
|
|
20
|
|
|
|
|
142
|
|
3544
|
|
|
|
|
|
|
|
3545
|
|
|
|
|
|
|
sub system : method Verb() { ## no critic (ProhibitBuiltInHomonyms) |
3546
|
4
|
|
|
4
|
1
|
22
|
my ( $self, undef, $verb, @args ) = __arguments( @_ ); # $opt unused |
3547
|
|
|
|
|
|
|
|
3548
|
|
|
|
|
|
|
@args = map { |
3549
|
4
|
|
|
|
|
17
|
bsd_glob( $_, GLOB_NOCHECK | GLOB_BRACE | GLOB_QUOTE ) |
|
8
|
|
|
|
|
297
|
|
3550
|
|
|
|
|
|
|
} @args; |
3551
|
4
|
|
|
|
|
18
|
my $stdout = $self->{frame}[-1]{localout}; |
3552
|
4
|
|
|
|
|
8
|
my @exported = keys %{ $self->{exported} }; |
|
4
|
|
|
|
|
25
|
|
3553
|
4
|
|
|
|
|
12
|
local @ENV{@exported} = map { $mutator{$_} ? $self->get( $_ ) : |
3554
|
5
|
100
|
|
|
|
26
|
$self->{exported}{$_} } @exported; |
3555
|
4
|
50
|
33
|
|
|
47
|
if ( defined $stdout && -t $stdout ) { |
3556
|
0
|
|
|
|
|
0
|
CORE::system {$verb} $verb, @args; |
|
0
|
|
|
|
|
0
|
|
3557
|
0
|
|
|
|
|
0
|
return; |
3558
|
|
|
|
|
|
|
} else { |
3559
|
4
|
|
|
|
|
72
|
$self->load_package( { fatal => 'wail' }, 'IPC::System::Simple' ); |
3560
|
4
|
|
|
|
|
20
|
return IPC::System::Simple::capturex( $verb, @args ); |
3561
|
|
|
|
|
|
|
} |
3562
|
20
|
|
|
20
|
|
8731
|
} |
|
20
|
|
|
|
|
66
|
|
|
20
|
|
|
|
|
128
|
|
3563
|
|
|
|
|
|
|
|
3564
|
|
|
|
|
|
|
sub time : method Verb() Tweak( -unsatisfied ) { ## no critic (ProhibitBuiltInHomonyms,RequireArgUnpacking) |
3565
|
1
|
50
|
|
1
|
1
|
4
|
my ($self, @args) = map { ARRAY_REF eq ref $_ ? @{ $_ } : $_ } @_; |
|
2
|
|
|
|
|
13
|
|
|
0
|
|
|
|
|
0
|
|
3566
|
1
|
50
|
|
|
|
7
|
$have_time_hires->() or $self->wail( 'Time::HiRes not available' ); |
3567
|
1
|
|
|
|
|
18
|
$self->_dispatch_check( time => $args[0] ); |
3568
|
1
|
|
|
|
|
10
|
my $start = Time::HiRes::time(); |
3569
|
|
|
|
|
|
|
# If we're inside an unsatisfied if() we do not do the timing, |
3570
|
|
|
|
|
|
|
# because dispatch() is probably a no-op. |
3571
|
|
|
|
|
|
|
$self->_in_unsatisfied_if() |
3572
|
|
|
|
|
|
|
or $self->_add_post_dispatch( |
3573
|
|
|
|
|
|
|
sub { |
3574
|
1
|
|
|
1
|
|
4
|
return sprintf "%.3f seconds\n", Time::HiRes::time() - $start; |
3575
|
|
|
|
|
|
|
}, |
3576
|
1
|
50
|
|
|
|
8
|
); |
3577
|
1
|
|
|
|
|
7
|
return $self->dispatch( @args ); |
3578
|
20
|
|
|
20
|
|
7507
|
} |
|
20
|
|
|
|
|
55
|
|
|
20
|
|
|
|
|
123
|
|
3579
|
|
|
|
|
|
|
|
3580
|
|
|
|
|
|
|
sub time_parser : Verb() { |
3581
|
0
|
0
|
|
0
|
1
|
0
|
splice @_, ( HASH_REF eq ref $_[1] ? 2 : 1 ), 0, 'time_parser'; |
3582
|
0
|
|
|
|
|
0
|
goto &_helper_handler; |
3583
|
20
|
|
|
20
|
|
5967
|
} |
|
20
|
|
|
|
|
46
|
|
|
20
|
|
|
|
|
145
|
|
3584
|
|
|
|
|
|
|
|
3585
|
|
|
|
|
|
|
sub tle : Verb( :compute __tle_options ) { |
3586
|
4
|
|
|
4
|
1
|
21
|
my ( $self, $opt, @args ) = __arguments( @_ ); |
3587
|
|
|
|
|
|
|
@args |
3588
|
|
|
|
|
|
|
and not $opt->{choose} |
3589
|
4
|
50
|
33
|
|
|
17
|
and $opt->{choose} = \@args; |
3590
|
|
|
|
|
|
|
|
3591
|
4
|
|
|
|
|
19
|
my $bodies = $self->__choose( $opt->{choose}, $self->{bodies} ); |
3592
|
4
|
|
|
|
|
10
|
@{ $bodies } = map { $_->[0] } |
|
5
|
|
|
|
|
123
|
|
3593
|
1
|
50
|
|
|
|
45
|
sort { $a->[1] <=> $b->[1] || $a->[2] <=> $b->[2] } |
3594
|
5
|
|
|
|
|
51
|
map { [ $_, $_->get( 'id' ), $_->get( 'epoch' ) ] } |
3595
|
4
|
|
|
|
|
11
|
@{ $bodies }; |
|
4
|
|
|
|
|
7
|
|
3596
|
4
|
|
|
|
|
12
|
my $tplt_name = delete $opt->{_template}; |
3597
|
4
|
|
|
|
|
12
|
return $self->__format_data( $tplt_name => $bodies, $opt ); |
3598
|
20
|
|
|
20
|
|
7555
|
} |
|
20
|
|
|
|
|
53
|
|
|
20
|
|
|
|
|
98
|
|
3599
|
|
|
|
|
|
|
|
3600
|
|
|
|
|
|
|
sub __tle_options { |
3601
|
4
|
|
|
4
|
|
11
|
my ( $self, $opt ) = @_; |
3602
|
|
|
|
|
|
|
return [ |
3603
|
4
|
|
|
|
|
23
|
qw{ choose=s@ }, |
3604
|
|
|
|
|
|
|
$self->_templates_to_options( tle => $opt ), |
3605
|
|
|
|
|
|
|
]; |
3606
|
|
|
|
|
|
|
} |
3607
|
|
|
|
|
|
|
|
3608
|
|
|
|
|
|
|
sub unexport : Verb() { |
3609
|
1
|
|
|
1
|
1
|
7
|
my ( $self, undef, @args ) = __arguments( @_ ); # $opt unused |
3610
|
|
|
|
|
|
|
|
3611
|
1
|
|
|
|
|
13
|
foreach my $name ( @args ) { |
3612
|
1
|
|
|
|
|
17
|
delete $self->{exported}{$name}; |
3613
|
|
|
|
|
|
|
} |
3614
|
1
|
|
|
|
|
4
|
return; |
3615
|
20
|
|
|
20
|
|
6198
|
} |
|
20
|
|
|
|
|
63
|
|
|
20
|
|
|
|
|
100
|
|
3616
|
|
|
|
|
|
|
|
3617
|
|
|
|
|
|
|
sub validate : Verb( quiet! ) { |
3618
|
1
|
|
|
1
|
1
|
11
|
my ( $self, $opt, @args ) = __arguments( @_ ); |
3619
|
|
|
|
|
|
|
|
3620
|
1
|
|
|
|
|
10
|
my $pass_start = $self->__parse_time ( |
3621
|
|
|
|
|
|
|
shift @args, $self->_get_day_noon()); |
3622
|
1
|
|
50
|
|
|
15
|
my $pass_end = $self->__parse_time (shift @args || '+7'); |
3623
|
1
|
50
|
|
|
|
6
|
$pass_start >= $pass_end |
3624
|
|
|
|
|
|
|
and $self->wail( 'End time must be after start time' ); |
3625
|
|
|
|
|
|
|
|
3626
|
1
|
50
|
|
|
|
8
|
@{ $self->{bodies} } |
|
1
|
|
|
|
|
6
|
|
3627
|
|
|
|
|
|
|
or $self->wail( 'No bodies selected' ); |
3628
|
|
|
|
|
|
|
|
3629
|
|
|
|
|
|
|
# Validate each body. |
3630
|
|
|
|
|
|
|
|
3631
|
1
|
|
|
|
|
3
|
my @valid; |
3632
|
1
|
|
|
|
|
6
|
foreach my $tle ( $self->_aggregate( $self->{bodies} ) ) { |
3633
|
2
|
100
|
|
|
|
1598
|
$tle->validate( $opt, $pass_start, $pass_end ) |
3634
|
|
|
|
|
|
|
and push @valid, $tle->members(); |
3635
|
|
|
|
|
|
|
} |
3636
|
|
|
|
|
|
|
|
3637
|
1
|
|
|
|
|
713
|
$self->{bodies} = \@valid; |
3638
|
|
|
|
|
|
|
|
3639
|
1
|
|
|
|
|
9
|
return; |
3640
|
20
|
|
|
20
|
|
7445
|
} |
|
20
|
|
|
|
|
44
|
|
|
20
|
|
|
|
|
93
|
|
3641
|
|
|
|
|
|
|
|
3642
|
|
|
|
|
|
|
sub version : Verb() { |
3643
|
0
|
|
|
0
|
1
|
0
|
return <<"EOD"; |
3644
|
|
|
|
|
|
|
|
3645
|
0
|
|
|
|
|
0
|
@{[__PACKAGE__]} $VERSION - Satellite pass predictor |
3646
|
0
|
|
|
|
|
0
|
based on Astro::Coord::ECI @{[Astro::Coord::ECI->VERSION]} |
3647
|
|
|
|
|
|
|
Copyright (C) 2009-2023 by Thomas R. Wyant, III |
3648
|
|
|
|
|
|
|
|
3649
|
|
|
|
|
|
|
EOD |
3650
|
20
|
|
|
20
|
|
5157
|
} |
|
20
|
|
|
|
|
59
|
|
|
20
|
|
|
|
|
108
|
|
3651
|
|
|
|
|
|
|
|
3652
|
|
|
|
|
|
|
######################################################################## |
3653
|
|
|
|
|
|
|
|
3654
|
|
|
|
|
|
|
# $self->_add_post_dispatch( $code_ref ); |
3655
|
|
|
|
|
|
|
|
3656
|
|
|
|
|
|
|
# Add a reference to code to be executed after the current interactive |
3657
|
|
|
|
|
|
|
# method is dispatched. All such code is executed, in the reverse of |
3658
|
|
|
|
|
|
|
# the order it was added. The only argument will be the invocant. |
3659
|
|
|
|
|
|
|
# Because it is added to the current execution frame, if the |
3660
|
|
|
|
|
|
|
# interactive method being dispatched is begin(), the code will be |
3661
|
|
|
|
|
|
|
# executed after the corresponding end(). Code to make the execution |
3662
|
|
|
|
|
|
|
# happen is, of course, in dispatch(). |
3663
|
|
|
|
|
|
|
sub _add_post_dispatch { |
3664
|
23
|
|
|
23
|
|
55
|
my ( $self, $code ) = @_; |
3665
|
23
|
|
50
|
|
|
31
|
push @{ $self->{frame}[-1]{post_dispatch} ||= [] }, $code; |
|
23
|
|
|
|
|
117
|
|
3666
|
23
|
|
|
|
|
47
|
return; |
3667
|
|
|
|
|
|
|
} |
3668
|
|
|
|
|
|
|
|
3669
|
|
|
|
|
|
|
# $self->_aggregate( $list_ref ); |
3670
|
|
|
|
|
|
|
|
3671
|
|
|
|
|
|
|
sub __add_to_observing_list { |
3672
|
5
|
|
|
5
|
|
13997
|
my ( $self, @args ) = @_; |
3673
|
5
|
|
|
|
|
29
|
foreach my $body ( @args ) { |
3674
|
10
|
50
|
|
|
|
212
|
embodies( $body, 'Astro::Coord::ECI::TLE' ) |
3675
|
|
|
|
|
|
|
and next; |
3676
|
0
|
|
|
|
|
0
|
my $id = $body->get( 'id' ); |
3677
|
0
|
0
|
|
|
|
0
|
defined $id |
3678
|
|
|
|
|
|
|
or $id = $body->get( 'name' ); |
3679
|
0
|
|
|
|
|
0
|
$self->wail( "Body $id is not a TLE" ); |
3680
|
|
|
|
|
|
|
} |
3681
|
5
|
|
|
|
|
125
|
push @{ $self->{bodies} }, @args; |
|
5
|
|
|
|
|
18
|
|
3682
|
5
|
|
|
|
|
22
|
return $self; |
3683
|
|
|
|
|
|
|
} |
3684
|
|
|
|
|
|
|
|
3685
|
|
|
|
|
|
|
# This is just a wrapper for |
3686
|
|
|
|
|
|
|
# Astro::Coord::ECI::TLE::Set->aggregate. |
3687
|
|
|
|
|
|
|
|
3688
|
|
|
|
|
|
|
sub _aggregate { |
3689
|
27
|
|
|
27
|
|
90
|
my ( $self, $bodies ) = @_; |
3690
|
27
|
|
|
|
|
130
|
local $Astro::Coord::ECI::TLE::Set::Singleton = $self->{singleton}; |
3691
|
27
|
|
|
|
|
62
|
return Astro::Coord::ECI::TLE::Set->aggregate ( @{ $bodies } ); |
|
27
|
|
|
|
|
243
|
|
3692
|
|
|
|
|
|
|
} |
3693
|
|
|
|
|
|
|
|
3694
|
|
|
|
|
|
|
# _apply_boolean_default( \%opt, $invert, @keys ); |
3695
|
|
|
|
|
|
|
# |
3696
|
|
|
|
|
|
|
# This subroutine defaults a set of boolean options. The keys in |
3697
|
|
|
|
|
|
|
# the set are specified in @keys, and the defined values are |
3698
|
|
|
|
|
|
|
# inverted before the defaults are applied if $invert is true. |
3699
|
|
|
|
|
|
|
# Nothing is returned. |
3700
|
|
|
|
|
|
|
|
3701
|
|
|
|
|
|
|
sub _apply_boolean_default { |
3702
|
44
|
|
|
44
|
|
166
|
my ( $self, $opt, $invert, @keys ) = @_; |
3703
|
44
|
|
|
|
|
116
|
my $state = my $found = 0; |
3704
|
44
|
|
|
|
|
105
|
foreach my $key ( @keys ) { |
3705
|
136
|
100
|
|
|
|
323
|
if ( exists $opt->{$key} ) { |
3706
|
8
|
|
|
|
|
16
|
$found++; |
3707
|
|
|
|
|
|
|
$invert |
3708
|
8
|
50
|
|
|
|
25
|
and $opt->{$key} = ( ! $opt->{$key} ); |
3709
|
8
|
100
|
|
|
|
30
|
$state |= ( $opt->{$key} ? 2 : 1 ); |
3710
|
|
|
|
|
|
|
} |
3711
|
|
|
|
|
|
|
} |
3712
|
|
|
|
|
|
|
1 == $state # Only negated options found |
3713
|
|
|
|
|
|
|
and @keys == $found # All options in group were specified |
3714
|
|
|
|
|
|
|
and $self->wail( 'May not negate all of ' . join ', ', map { |
3715
|
44
|
50
|
66
|
|
|
177
|
"-$_" } @keys ); |
|
0
|
|
|
|
|
0
|
|
3716
|
44
|
|
|
|
|
89
|
my $default = $state < 2; |
3717
|
44
|
|
|
|
|
79
|
foreach my $key ( @keys ) { |
3718
|
|
|
|
|
|
|
exists $opt->{$key} |
3719
|
136
|
100
|
|
|
|
419
|
or $opt->{$key} = $default; |
3720
|
|
|
|
|
|
|
} |
3721
|
44
|
|
|
|
|
140
|
return; |
3722
|
|
|
|
|
|
|
} |
3723
|
|
|
|
|
|
|
|
3724
|
|
|
|
|
|
|
# $self->_attribute_exists( $name, %arg ); |
3725
|
|
|
|
|
|
|
# |
3726
|
|
|
|
|
|
|
# This method returns true if an accessor for the given attribute |
3727
|
|
|
|
|
|
|
# exists, and croaks otherwise. |
3728
|
|
|
|
|
|
|
# Attributes in the %level1_attr hash fail unless in level1 mode |
3729
|
|
|
|
|
|
|
# Named arguments: |
3730
|
|
|
|
|
|
|
# query: if true, returns false if attribute does not exist |
3731
|
|
|
|
|
|
|
|
3732
|
|
|
|
|
|
|
{ |
3733
|
|
|
|
|
|
|
my %level1_attr = map { $_ => 1 } qw{ sun }; |
3734
|
|
|
|
|
|
|
|
3735
|
|
|
|
|
|
|
sub _attribute_exists { |
3736
|
1280
|
|
|
1280
|
|
2632
|
my ( $self, $name, %arg ) = @_; |
3737
|
|
|
|
|
|
|
exists $accessor{$name} |
3738
|
|
|
|
|
|
|
and ( ! $level1_attr{$name} || $self->{frame}[-1]{level1} ) |
3739
|
1280
|
50
|
33
|
|
|
6849
|
and return $accessor{$name}; |
|
|
|
33
|
|
|
|
|
3740
|
|
|
|
|
|
|
$arg{query} |
3741
|
0
|
0
|
|
|
|
0
|
or $self->wail("No such attribute as '$name'"); |
3742
|
0
|
|
|
|
|
0
|
return; |
3743
|
|
|
|
|
|
|
} |
3744
|
|
|
|
|
|
|
} |
3745
|
|
|
|
|
|
|
|
3746
|
|
|
|
|
|
|
{ |
3747
|
|
|
|
|
|
|
|
3748
|
|
|
|
|
|
|
my %spacetrack_attributes; |
3749
|
|
|
|
|
|
|
$have_astro_spacetrack->() |
3750
|
|
|
|
|
|
|
and %spacetrack_attributes = map { $_ => 1 } |
3751
|
|
|
|
|
|
|
Astro::SpaceTrack->attribute_names(); |
3752
|
|
|
|
|
|
|
|
3753
|
|
|
|
|
|
|
my %special = ( |
3754
|
|
|
|
|
|
|
formatter => sub { |
3755
|
|
|
|
|
|
|
my ( $obj, $attr ) = @_; |
3756
|
|
|
|
|
|
|
$obj->can( $attr ) |
3757
|
|
|
|
|
|
|
or return NULL; |
3758
|
|
|
|
|
|
|
return $obj->$attr(); |
3759
|
|
|
|
|
|
|
}, |
3760
|
|
|
|
|
|
|
spacetrack => sub { |
3761
|
|
|
|
|
|
|
my ( $obj, $attr ) = @_; |
3762
|
|
|
|
|
|
|
$spacetrack_attributes{$attr} |
3763
|
|
|
|
|
|
|
or return NULL; |
3764
|
|
|
|
|
|
|
return $obj->getv( $attr ); |
3765
|
|
|
|
|
|
|
}, |
3766
|
|
|
|
|
|
|
time_parser => sub { |
3767
|
|
|
|
|
|
|
my ( $obj, $attr ) = @_; |
3768
|
|
|
|
|
|
|
$obj->can( $attr ) |
3769
|
|
|
|
|
|
|
or return NULL; |
3770
|
|
|
|
|
|
|
return $obj->$attr(); |
3771
|
|
|
|
|
|
|
}, |
3772
|
|
|
|
|
|
|
); |
3773
|
|
|
|
|
|
|
|
3774
|
|
|
|
|
|
|
# my $value = $self->_attribute_value( $name ); |
3775
|
|
|
|
|
|
|
# |
3776
|
|
|
|
|
|
|
# Return an attribute value. If the attribute is 'formatter', |
3777
|
|
|
|
|
|
|
# 'spacetrack' or 'time_parser' you can specify a dot and the name |
3778
|
|
|
|
|
|
|
# of an attribute of the relevant object, e.g. spacetrack.username. |
3779
|
|
|
|
|
|
|
# If the attribute does not exist you get back manifest constant |
3780
|
|
|
|
|
|
|
# NULL, which is a reference to undef blessed into class 'Null'. |
3781
|
|
|
|
|
|
|
sub _attribute_value { |
3782
|
43
|
|
|
43
|
|
86
|
my ( $self, $name ) = @_; |
3783
|
43
|
|
|
|
|
266
|
my ( $attr, $sub ) = split qr{ [.] }smx, $name, 2; |
3784
|
43
|
100
|
|
|
|
180
|
$accessor{$attr} |
3785
|
|
|
|
|
|
|
or return NULL; |
3786
|
9
|
|
|
|
|
22
|
my $rslt = $self->get( $attr ); |
3787
|
9
|
100
|
|
|
|
34
|
if ( defined $sub ) { |
3788
|
|
|
|
|
|
|
$rslt |
3789
|
2
|
50
|
33
|
|
|
28
|
and my $code = $special{$attr} |
3790
|
|
|
|
|
|
|
or return NULL; |
3791
|
2
|
|
|
|
|
9
|
$rslt = $code->( $rslt, $sub ); |
3792
|
|
|
|
|
|
|
} |
3793
|
9
|
|
|
|
|
33
|
return $rslt; |
3794
|
|
|
|
|
|
|
} |
3795
|
|
|
|
|
|
|
} |
3796
|
|
|
|
|
|
|
|
3797
|
|
|
|
|
|
|
# Documented in POD |
3798
|
|
|
|
|
|
|
|
3799
|
|
|
|
|
|
|
{ |
3800
|
|
|
|
|
|
|
my %chooser = ( |
3801
|
|
|
|
|
|
|
'' => sub { |
3802
|
|
|
|
|
|
|
my ( $sel ) = @_; |
3803
|
|
|
|
|
|
|
my @rslt; |
3804
|
|
|
|
|
|
|
foreach my $s ( split qr{ \s* , \s* }smx, $sel ) { |
3805
|
|
|
|
|
|
|
if ( $s =~ m/ \D /smx || $s < 1000 ) { |
3806
|
|
|
|
|
|
|
my $re = qr{\Q$s\E}i; |
3807
|
|
|
|
|
|
|
push @rslt, sub { |
3808
|
|
|
|
|
|
|
my ( $tle, $context ) = @_; |
3809
|
|
|
|
|
|
|
$context->{name} ||= $tle->get( 'name' ); |
3810
|
|
|
|
|
|
|
defined $context->{name} |
3811
|
|
|
|
|
|
|
or return; |
3812
|
|
|
|
|
|
|
return $context->{name} =~ $re; |
3813
|
|
|
|
|
|
|
}; |
3814
|
|
|
|
|
|
|
} else { |
3815
|
|
|
|
|
|
|
push @rslt, sub { |
3816
|
|
|
|
|
|
|
my ( $tle, $context ) = @_; |
3817
|
|
|
|
|
|
|
$context->{id} ||= $tle->get( 'id' ); |
3818
|
|
|
|
|
|
|
return $context->{id} == $s; |
3819
|
|
|
|
|
|
|
}; |
3820
|
|
|
|
|
|
|
} |
3821
|
|
|
|
|
|
|
} |
3822
|
|
|
|
|
|
|
return @rslt; |
3823
|
|
|
|
|
|
|
}, |
3824
|
|
|
|
|
|
|
CODE_REF() => sub { |
3825
|
|
|
|
|
|
|
my ( $sel ) = @_; |
3826
|
|
|
|
|
|
|
return $sel; |
3827
|
|
|
|
|
|
|
}, |
3828
|
|
|
|
|
|
|
REGEXP_REF() => sub { |
3829
|
|
|
|
|
|
|
my ( $sel ) = @_; |
3830
|
|
|
|
|
|
|
return sub { |
3831
|
|
|
|
|
|
|
my ( $tle, $context ) = @_; |
3832
|
|
|
|
|
|
|
$context->{name} ||= $tle->get( 'name' ); |
3833
|
|
|
|
|
|
|
return $context->{name} =~ $sel; |
3834
|
|
|
|
|
|
|
}; |
3835
|
|
|
|
|
|
|
}, |
3836
|
|
|
|
|
|
|
); |
3837
|
|
|
|
|
|
|
|
3838
|
|
|
|
|
|
|
sub __choose { |
3839
|
45
|
|
|
45
|
|
295
|
my ( $self, @args ) = @_; |
3840
|
45
|
100
|
|
|
|
210
|
my $opt = HASH_REF eq ref $args[0] ? shift @args : {}; |
3841
|
45
|
|
|
|
|
124
|
my $choice = shift @args; |
3842
|
45
|
100
|
|
|
|
152
|
defined $choice |
3843
|
|
|
|
|
|
|
or $choice = []; |
3844
|
45
|
50
|
|
|
|
160
|
ARRAY_REF eq ref $choice |
3845
|
|
|
|
|
|
|
or $self->weep( 'Choice invalid' ); |
3846
|
45
|
|
|
|
|
102
|
my @rslt; |
3847
|
|
|
|
|
|
|
my @selector; |
3848
|
45
|
|
|
|
|
96
|
foreach my $sel ( @{ $choice } ) { |
|
45
|
|
|
|
|
190
|
|
3849
|
5
|
|
|
|
|
14
|
my $ref = ref $sel; |
3850
|
5
|
50
|
|
|
|
21
|
my $code = $chooser{$ref} |
3851
|
|
|
|
|
|
|
or $self->weep( "$ref not supported as chooser" ); |
3852
|
5
|
|
|
|
|
23
|
push @selector, $code->( $sel ); |
3853
|
|
|
|
|
|
|
} |
3854
|
|
|
|
|
|
|
|
3855
|
|
|
|
|
|
|
$opt->{bodies} |
3856
|
|
|
|
|
|
|
and push @args, |
3857
|
45
|
100
|
|
|
|
192
|
$self->_aggregate( $self->{bodies} ); |
3858
|
|
|
|
|
|
|
$opt->{sky} |
3859
|
45
|
100
|
|
|
|
743
|
and push @args, $self->{sky}; |
3860
|
|
|
|
|
|
|
|
3861
|
45
|
100
|
|
|
|
99
|
@args = map { ARRAY_REF eq ref $_ ? @{ $_ } : $_ } @args; |
|
51
|
|
|
|
|
159
|
|
|
43
|
|
|
|
|
154
|
|
3862
|
|
|
|
|
|
|
|
3863
|
|
|
|
|
|
|
not @selector |
3864
|
45
|
100
|
|
|
|
362
|
and return wantarray ? @args : \@args; |
|
|
100
|
|
|
|
|
|
3865
|
|
|
|
|
|
|
|
3866
|
5
|
|
|
|
|
13
|
foreach my $tle ( @args ) { |
3867
|
10
|
50
|
|
|
|
30
|
ARRAY_REF eq ref $tle |
3868
|
|
|
|
|
|
|
and $self->weep( 'Schwartzian-transform objects not supported' ); |
3869
|
|
|
|
|
|
|
|
3870
|
10
|
|
|
|
|
25
|
my $match = $opt->{invert}; |
3871
|
10
|
|
|
|
|
20
|
my $context = {}; |
3872
|
10
|
|
|
|
|
22
|
foreach my $sel ( @selector ) { |
3873
|
10
|
100
|
|
|
|
27
|
$sel->( $tle, $context ) |
3874
|
|
|
|
|
|
|
or next; |
3875
|
4
|
|
|
|
|
10
|
$match = !$match; |
3876
|
4
|
|
|
|
|
9
|
last; |
3877
|
|
|
|
|
|
|
} |
3878
|
|
|
|
|
|
|
|
3879
|
10
|
100
|
|
|
|
35
|
$match and push @rslt, $tle; |
3880
|
|
|
|
|
|
|
} |
3881
|
|
|
|
|
|
|
|
3882
|
5
|
100
|
|
|
|
62
|
return wantarray ? @rslt : \@rslt; |
3883
|
|
|
|
|
|
|
} |
3884
|
|
|
|
|
|
|
|
3885
|
|
|
|
|
|
|
} |
3886
|
|
|
|
|
|
|
|
3887
|
|
|
|
|
|
|
# $self->_deprecation_notice( $type, $name ); |
3888
|
|
|
|
|
|
|
# |
3889
|
|
|
|
|
|
|
# This method centralizes deprecation. Type is 'attribute' or |
3890
|
|
|
|
|
|
|
# 'method'. Deprecation is driven of the %deprecate hash. Values |
3891
|
|
|
|
|
|
|
# are: |
3892
|
|
|
|
|
|
|
# false - no warning |
3893
|
|
|
|
|
|
|
# 1 - warn on first use |
3894
|
|
|
|
|
|
|
# 2 - warn on each use |
3895
|
|
|
|
|
|
|
# 3 - die on each use. |
3896
|
|
|
|
|
|
|
# |
3897
|
|
|
|
|
|
|
# $self->_deprecation_in_progress( $type, $name ) |
3898
|
|
|
|
|
|
|
# |
3899
|
|
|
|
|
|
|
# This method returns true if the deprecation is in progress. In |
3900
|
|
|
|
|
|
|
# fact it returns the deprecation level. |
3901
|
|
|
|
|
|
|
|
3902
|
|
|
|
|
|
|
{ |
3903
|
|
|
|
|
|
|
|
3904
|
|
|
|
|
|
|
my %deprecate = ( |
3905
|
|
|
|
|
|
|
attribute => { |
3906
|
|
|
|
|
|
|
country => 0, |
3907
|
|
|
|
|
|
|
date_format => 0, |
3908
|
|
|
|
|
|
|
desired_equinox_dynamical => 0, |
3909
|
|
|
|
|
|
|
explicit_macro_delete => 0, |
3910
|
|
|
|
|
|
|
gmt => 0, |
3911
|
|
|
|
|
|
|
local_coord => 0, |
3912
|
|
|
|
|
|
|
perltime => 0, |
3913
|
|
|
|
|
|
|
time_format => 0, |
3914
|
|
|
|
|
|
|
tz => 0, |
3915
|
|
|
|
|
|
|
}, |
3916
|
|
|
|
|
|
|
method => { |
3917
|
|
|
|
|
|
|
st => 0, |
3918
|
|
|
|
|
|
|
}, |
3919
|
|
|
|
|
|
|
status => { |
3920
|
|
|
|
|
|
|
iridium => 3, |
3921
|
|
|
|
|
|
|
}, |
3922
|
|
|
|
|
|
|
); |
3923
|
|
|
|
|
|
|
|
3924
|
|
|
|
|
|
|
sub _deprecation_notice { |
3925
|
1277
|
|
|
1277
|
|
2846
|
my ( $self, $type, $name, $repl ) = @_; |
3926
|
1277
|
50
|
|
|
|
3309
|
$deprecate{$type} or return; |
3927
|
1277
|
50
|
|
|
|
3366
|
$deprecate{$type}{$name} or return; |
3928
|
|
|
|
|
|
|
my $msg = sprintf 'The %s %s is %s', $name, $type, |
3929
|
0
|
0
|
|
|
|
0
|
$deprecate{$type}{$name} > 2 ? 'removed' : 'deprecated'; |
3930
|
0
|
0
|
|
|
|
0
|
defined $repl |
3931
|
|
|
|
|
|
|
and $msg .= "; use $repl instead"; |
3932
|
0
|
0
|
|
|
|
0
|
$deprecate{$type}{$name} >= 3 |
3933
|
|
|
|
|
|
|
and $self->wail( $msg ); |
3934
|
0
|
0
|
|
|
|
0
|
warnings::enabled( 'deprecated' ) |
3935
|
|
|
|
|
|
|
and $self->whinge( $msg ); |
3936
|
|
|
|
|
|
|
$deprecate{$type}{$name} == 1 |
3937
|
0
|
0
|
|
|
|
0
|
and $deprecate{$type}{$name} = 0; |
3938
|
0
|
|
|
|
|
0
|
return; |
3939
|
|
|
|
|
|
|
} |
3940
|
|
|
|
|
|
|
|
3941
|
|
|
|
|
|
|
sub _deprecation_in_progress { |
3942
|
0
|
|
|
0
|
|
0
|
my ( undef, $type, $name ) = @_; # Invocant unused |
3943
|
0
|
0
|
|
|
|
0
|
$deprecate{$type} or return; |
3944
|
0
|
|
|
|
|
0
|
return $deprecate{$type}{$name}; |
3945
|
|
|
|
|
|
|
} |
3946
|
|
|
|
|
|
|
|
3947
|
|
|
|
|
|
|
} |
3948
|
|
|
|
|
|
|
|
3949
|
|
|
|
|
|
|
# my ( $obj ) = $self->_drop_from_sky( $name ); |
3950
|
|
|
|
|
|
|
# The return is an array containing the dropped body, or nothing if the |
3951
|
|
|
|
|
|
|
# body was not found. |
3952
|
|
|
|
|
|
|
sub _drop_from_sky { |
3953
|
1
|
|
|
1
|
|
3
|
my ( $self, $name ) = @_; |
3954
|
1
|
50
|
|
|
|
10
|
defined( my $inx = $self->_find_in_sky( $name ) ) |
3955
|
|
|
|
|
|
|
or return; |
3956
|
1
|
|
|
|
|
41
|
return splice @{ $self->{sky} }, $inx, 1; |
|
1
|
|
|
|
|
5
|
|
3957
|
|
|
|
|
|
|
} |
3958
|
|
|
|
|
|
|
|
3959
|
|
|
|
|
|
|
# $fh = $self->_file_opener( $name, $mode ); |
3960
|
|
|
|
|
|
|
# |
3961
|
|
|
|
|
|
|
# This method opens the given file, returning the handle. If the |
3962
|
|
|
|
|
|
|
# mode is output, the current value of output_layers is appended. |
3963
|
|
|
|
|
|
|
# An exception is thrown if the file can not be opened. |
3964
|
|
|
|
|
|
|
|
3965
|
|
|
|
|
|
|
sub _file_opener { |
3966
|
1
|
|
|
1
|
|
4
|
my ( $self, $name, $mode ) = @_; |
3967
|
|
|
|
|
|
|
|
3968
|
|
|
|
|
|
|
# NOTE special case for &1 (stdout) and &2 (stderr). |
3969
|
|
|
|
|
|
|
my $fh = ( $name =~ m/ \A & ( [12] ) \z /smx ) ? |
3970
|
|
|
|
|
|
|
[ |
3971
|
|
|
|
|
|
|
undef, |
3972
|
1
|
50
|
0
|
|
|
11
|
$self->{frame}[-1]{localout} || \*STDOUT, |
|
|
50
|
|
|
|
|
|
3973
|
|
|
|
|
|
|
\*STDERR, |
3974
|
|
|
|
|
|
|
]->[ $1 ] : |
3975
|
|
|
|
|
|
|
IO::File->new( $name, $mode ) |
3976
|
|
|
|
|
|
|
or $self->wail( "Unable to open $name: $!" ); |
3977
|
|
|
|
|
|
|
|
3978
|
1
|
50
|
|
|
|
184
|
if ( $mode =~ m/ \A (?: [+>] | [|] - ) /smx ) { |
3979
|
|
|
|
|
|
|
|
3980
|
1
|
|
|
|
|
6
|
my $layers = $self->get( 'output_layers' ); |
3981
|
1
|
50
|
33
|
|
|
11
|
if ( defined $layers && '' ne $layers ) { |
3982
|
1
|
50
|
|
|
|
13
|
binmode $fh, $layers |
3983
|
|
|
|
|
|
|
or $self->wail( |
3984
|
|
|
|
|
|
|
"Unable to set '$layers' on $name: $!" ); |
3985
|
|
|
|
|
|
|
} |
3986
|
|
|
|
|
|
|
} |
3987
|
|
|
|
|
|
|
|
3988
|
1
|
|
|
|
|
77
|
return $fh; |
3989
|
|
|
|
|
|
|
} |
3990
|
|
|
|
|
|
|
|
3991
|
|
|
|
|
|
|
# $code = $self->_file_reader( $file, \%opt ); |
3992
|
|
|
|
|
|
|
# |
3993
|
|
|
|
|
|
|
# This method returns a code snippet that returns the contents of |
3994
|
|
|
|
|
|
|
# the file one line at a time. The $file can be any of: |
3995
|
|
|
|
|
|
|
# |
3996
|
|
|
|
|
|
|
# * An open handle |
3997
|
|
|
|
|
|
|
# * A URL (if LWP::UserAgent can be loaded) |
3998
|
|
|
|
|
|
|
# * A file name |
3999
|
|
|
|
|
|
|
# * A scalar reference |
4000
|
|
|
|
|
|
|
# * An array reference |
4001
|
|
|
|
|
|
|
# * A code reference, which is returned unmodified |
4002
|
|
|
|
|
|
|
# |
4003
|
|
|
|
|
|
|
# The code snippet will return undef at end-of-file. |
4004
|
|
|
|
|
|
|
# |
4005
|
|
|
|
|
|
|
# The following keys in %opt are recognized: |
4006
|
|
|
|
|
|
|
# {encoding} specifies the encoding of the file. How this is used |
4007
|
|
|
|
|
|
|
# on the $file argument as follows: |
4008
|
|
|
|
|
|
|
# * An open handle -- unused |
4009
|
|
|
|
|
|
|
# * A URL ----------- unused (encoding taken from HTTP::Response) |
4010
|
|
|
|
|
|
|
# * A file name ----- used (default is utf-8) |
4011
|
|
|
|
|
|
|
# * A scalar ref ---- used (default is un-encoded) |
4012
|
|
|
|
|
|
|
# * An array ref ---- unused |
4013
|
|
|
|
|
|
|
# * A code ref ------ unused |
4014
|
|
|
|
|
|
|
# {glob} causes the contents of the file to be returned, rather |
4015
|
|
|
|
|
|
|
# than a reader. |
4016
|
|
|
|
|
|
|
# {optional} causes the code to simply return on an error, rather |
4017
|
|
|
|
|
|
|
# than failing. |
4018
|
|
|
|
|
|
|
|
4019
|
|
|
|
|
|
|
sub _file_reader { |
4020
|
25
|
|
|
25
|
|
3411
|
my ( $self, $file, $opt ) = @_; |
4021
|
|
|
|
|
|
|
|
4022
|
25
|
100
|
|
|
|
119
|
if ( openhandle( $file ) ) { |
4023
|
|
|
|
|
|
|
$opt->{glob} |
4024
|
2
|
100
|
|
1
|
|
14
|
or return sub { return scalar <$file> }; |
|
1
|
|
|
|
|
20
|
|
4025
|
1
|
|
|
|
|
7
|
local $/ = undef; |
4026
|
1
|
|
|
|
|
27
|
return scalar <$file>; |
4027
|
|
|
|
|
|
|
} |
4028
|
|
|
|
|
|
|
|
4029
|
23
|
|
|
|
|
73
|
my $ref = ref $file; |
4030
|
23
|
50
|
|
|
|
146
|
my $code = $self->can( "_file_reader_$ref" ) |
4031
|
|
|
|
|
|
|
or $self->wail( sprintf "Opening a $ref ref is unsupported" ); |
4032
|
|
|
|
|
|
|
|
4033
|
23
|
|
|
|
|
129
|
goto &$code; |
4034
|
|
|
|
|
|
|
} |
4035
|
|
|
|
|
|
|
|
4036
|
|
|
|
|
|
|
# Most of the following are called using '$self->can( |
4037
|
|
|
|
|
|
|
# "_file_reader_$ref" )', and there is no way a static analysis tool can |
4038
|
|
|
|
|
|
|
# find such calls. So we just have to exempt them from Perl::Critic |
4039
|
|
|
|
|
|
|
|
4040
|
|
|
|
|
|
|
sub _file_reader_ { ## no critic (ProhibitUnusedPrivateSubroutines) |
4041
|
14
|
|
|
14
|
|
49
|
my ( $self, $file, $opt ) = @_; |
4042
|
|
|
|
|
|
|
|
4043
|
14
|
50
|
|
|
|
50
|
defined $file |
4044
|
|
|
|
|
|
|
and chomp $file; |
4045
|
|
|
|
|
|
|
|
4046
|
14
|
50
|
33
|
|
|
129
|
if ( ! defined $file || ! ref $file && '' eq $file ) { |
|
|
|
33
|
|
|
|
|
4047
|
0
|
0
|
|
|
|
0
|
$opt->{optional} and return; |
4048
|
0
|
|
|
|
|
0
|
$self->wail( 'Defined file required' ); |
4049
|
|
|
|
|
|
|
} |
4050
|
|
|
|
|
|
|
|
4051
|
14
|
50
|
|
|
|
75
|
if ( $self->_file_reader__validate_url( $file ) ) { |
4052
|
0
|
|
|
|
|
0
|
my $ua = LWP::UserAgent->new(); |
4053
|
0
|
|
|
|
|
0
|
my $resp = $ua->get( $file ); |
4054
|
|
|
|
|
|
|
$resp->is_success() |
4055
|
0
|
0
|
|
|
|
0
|
or do { |
4056
|
0
|
0
|
|
|
|
0
|
$opt->{optional} and return; |
4057
|
0
|
|
|
|
|
0
|
$self->wail( "Failed to retrieve $file: ", |
4058
|
|
|
|
|
|
|
$resp->status_line() ); |
4059
|
|
|
|
|
|
|
}; |
4060
|
0
|
0
|
|
|
|
0
|
$opt->{glob} and return $resp->decoded_content(); |
4061
|
0
|
|
|
|
|
0
|
$opt = { %{ $opt }, encoding => $resp->content_charset() }; |
|
0
|
|
|
|
|
0
|
|
4062
|
0
|
|
|
|
|
0
|
return $self->_file_reader( |
4063
|
|
|
|
|
|
|
\( scalar $resp->content() ), |
4064
|
|
|
|
|
|
|
$opt, |
4065
|
|
|
|
|
|
|
); |
4066
|
|
|
|
|
|
|
} else { |
4067
|
14
|
|
50
|
|
|
106
|
my $encoding = $opt->{encoding} || 'utf-8'; |
4068
|
|
|
|
|
|
|
my $fh = IO::File->new( |
4069
|
|
|
|
|
|
|
$self->expand_tilde( $file ), |
4070
|
|
|
|
|
|
|
"<:encoding($encoding)", |
4071
|
14
|
100
|
|
|
|
96
|
) or do { |
4072
|
3
|
100
|
|
|
|
365
|
$opt->{optional} and return; |
4073
|
2
|
|
|
|
|
37
|
$self->wail( "Failed to open $file: $!" ); |
4074
|
|
|
|
|
|
|
}; |
4075
|
|
|
|
|
|
|
$opt->{glob} |
4076
|
11
|
100
|
|
16
|
|
3018
|
or return sub { return scalar <$fh> }; |
|
16
|
|
|
|
|
327
|
|
4077
|
7
|
|
|
|
|
59
|
local $/ = undef; |
4078
|
7
|
|
|
|
|
370
|
return scalar <$fh>; |
4079
|
|
|
|
|
|
|
} |
4080
|
|
|
|
|
|
|
} |
4081
|
|
|
|
|
|
|
|
4082
|
|
|
|
|
|
|
sub _file_reader__validate_url { |
4083
|
14
|
|
|
14
|
|
48
|
my ( undef, $url ) = @_; # Invocant unused |
4084
|
|
|
|
|
|
|
|
4085
|
14
|
50
|
|
|
|
91
|
load_package( 'LWP::UserAgent' ) |
4086
|
|
|
|
|
|
|
or return; |
4087
|
|
|
|
|
|
|
|
4088
|
0
|
0
|
|
|
|
0
|
load_package( 'URI' ) |
4089
|
|
|
|
|
|
|
or return; |
4090
|
|
|
|
|
|
|
|
4091
|
0
|
0
|
|
|
|
0
|
load_package( 'LWP::Protocol' ) |
4092
|
|
|
|
|
|
|
or return; |
4093
|
|
|
|
|
|
|
|
4094
|
0
|
0
|
|
|
|
0
|
my $obj = URI->new( $url ) |
4095
|
|
|
|
|
|
|
or return; |
4096
|
0
|
0
|
|
|
|
0
|
$obj->can( 'authority' ) |
4097
|
|
|
|
|
|
|
or return 1; |
4098
|
|
|
|
|
|
|
|
4099
|
0
|
0
|
|
|
|
0
|
defined( my $scheme = $obj->scheme() ) |
4100
|
|
|
|
|
|
|
or return; |
4101
|
0
|
0
|
|
|
|
0
|
LWP::Protocol::implementor( $scheme ) |
4102
|
|
|
|
|
|
|
or return; |
4103
|
|
|
|
|
|
|
|
4104
|
0
|
|
|
|
|
0
|
return 1; |
4105
|
|
|
|
|
|
|
} |
4106
|
|
|
|
|
|
|
|
4107
|
|
|
|
|
|
|
sub _file_reader_ARRAY { ## no critic (ProhibitUnusedPrivateSubroutines) |
4108
|
5
|
|
|
5
|
|
15
|
my ( undef, $file, $opt ) = @_; # Invocant unused |
4109
|
|
|
|
|
|
|
|
4110
|
5
|
|
|
|
|
8
|
my $inx = 0; |
4111
|
|
|
|
|
|
|
$opt->{glob} |
4112
|
5
|
100
|
|
11
|
|
34
|
or return sub { return $file->[$inx++] }; |
|
11
|
|
|
|
|
24
|
|
4113
|
1
|
|
|
|
|
3
|
my $buffer; |
4114
|
1
|
|
|
|
|
8
|
foreach ( @{ $file } ) { |
|
1
|
|
|
|
|
3
|
|
4115
|
5
|
|
|
|
|
11
|
$buffer .= $_; |
4116
|
5
|
50
|
|
|
|
19
|
$buffer =~ m/ \n \z /smx |
4117
|
|
|
|
|
|
|
or $buffer .= "\n"; |
4118
|
|
|
|
|
|
|
} |
4119
|
1
|
|
|
|
|
5
|
return $buffer; |
4120
|
|
|
|
|
|
|
} |
4121
|
|
|
|
|
|
|
|
4122
|
|
|
|
|
|
|
sub _file_reader_CODE { ## no critic (ProhibitUnusedPrivateSubroutines) |
4123
|
2
|
|
|
2
|
|
6
|
my ( undef, $file, $opt ) = @_; # Invocant unused |
4124
|
|
|
|
|
|
|
$opt->{glob} |
4125
|
2
|
100
|
|
|
|
9
|
or return $file; |
4126
|
1
|
|
|
|
|
3
|
my $buffer; |
4127
|
1
|
|
|
|
|
3
|
local $_; |
4128
|
1
|
|
|
|
|
34
|
while ( defined( $_ = $file->() ) ) { |
4129
|
5
|
|
|
|
|
27
|
$buffer .= $_; |
4130
|
5
|
50
|
|
|
|
20
|
$buffer =~ m/ \n \z /smx |
4131
|
|
|
|
|
|
|
or $buffer .= "\n"; |
4132
|
|
|
|
|
|
|
} |
4133
|
1
|
|
|
|
|
8
|
return $buffer; |
4134
|
|
|
|
|
|
|
} |
4135
|
|
|
|
|
|
|
|
4136
|
|
|
|
|
|
|
sub _file_reader_SCALAR { ## no critic (ProhibitUnusedPrivateSubroutines) |
4137
|
2
|
|
|
2
|
|
6
|
my ( $self, $file, $opt ) = @_; |
4138
|
|
|
|
|
|
|
|
4139
|
|
|
|
|
|
|
$opt->{glob} |
4140
|
2
|
100
|
|
|
|
8
|
and return ${ $file }; |
|
1
|
|
|
|
|
7
|
|
4141
|
1
|
50
|
|
|
|
4
|
my $mode = $opt->{encoding} ? "<:encoding($opt->{encoding})" : '<'; |
4142
|
|
|
|
|
|
|
|
4143
|
1
|
50
|
|
|
|
7
|
my $fh = IO::File->new( $file, $mode ) # Needs IO::File 1.14. |
4144
|
|
|
|
|
|
|
or $self->wail( "Failed to open SCALAR ref: $!" ); |
4145
|
|
|
|
|
|
|
|
4146
|
1
|
|
|
1
|
|
821
|
return sub { return scalar <$fh> }; |
|
1
|
|
|
|
|
9
|
|
4147
|
|
|
|
|
|
|
} |
4148
|
|
|
|
|
|
|
|
4149
|
|
|
|
|
|
|
# $inx = $self->_find_in_sky( $name ) |
4150
|
|
|
|
|
|
|
# The return is the index of the named body in @{ $self->{sky} }, or |
4151
|
|
|
|
|
|
|
# undef if it is not present. 'Sun' and 'Moon' are special cases; |
4152
|
|
|
|
|
|
|
# everything else is presumed to be found by name. |
4153
|
|
|
|
|
|
|
sub _find_in_sky { |
4154
|
6
|
|
|
6
|
|
22
|
my ( $self, $name ) = @_; |
4155
|
|
|
|
|
|
|
|
4156
|
6
|
|
|
|
|
86
|
my $re = qr/ \A \Q$name\E \z /smxi; |
4157
|
6
|
|
|
|
|
14
|
foreach my $inx ( 0 .. $#{ $self->{sky} } ) { |
|
6
|
|
|
|
|
28
|
|
4158
|
8
|
100
|
|
|
|
124
|
$self->{sky}[$inx]->get( 'name' ) =~ $re |
4159
|
|
|
|
|
|
|
and return $inx; |
4160
|
|
|
|
|
|
|
} |
4161
|
5
|
|
|
|
|
116
|
return; |
4162
|
|
|
|
|
|
|
} |
4163
|
|
|
|
|
|
|
|
4164
|
|
|
|
|
|
|
# Documented in POD |
4165
|
|
|
|
|
|
|
|
4166
|
|
|
|
|
|
|
sub __format_data { |
4167
|
41
|
|
|
41
|
|
4494
|
my ( $self, $action, $data, $opt ) = @_; |
4168
|
41
|
|
|
|
|
221
|
return $self->_get_formatter_object( $opt )->format( |
4169
|
|
|
|
|
|
|
sp => $self, |
4170
|
|
|
|
|
|
|
template => $action, |
4171
|
|
|
|
|
|
|
data => $data, |
4172
|
|
|
|
|
|
|
opt => $opt, |
4173
|
|
|
|
|
|
|
); |
4174
|
|
|
|
|
|
|
} |
4175
|
|
|
|
|
|
|
|
4176
|
|
|
|
|
|
|
# $frames = $satpass2->_frame_push($type, \@args); |
4177
|
|
|
|
|
|
|
# |
4178
|
|
|
|
|
|
|
# This method pushes a context frame on the stack. The $type |
4179
|
|
|
|
|
|
|
# describes the frame, and goes in the frame's {type} entry, but |
4180
|
|
|
|
|
|
|
# is currently unused. The \@args entry goes in the {args} key, |
4181
|
|
|
|
|
|
|
# and is the basis of argument expansion. The return is the number |
4182
|
|
|
|
|
|
|
# of frames that were on the stack _BEFORE_ the now-current frame |
4183
|
|
|
|
|
|
|
# was added to the stack. This gets passed to _frame_pop() to |
4184
|
|
|
|
|
|
|
# restore the context stack to its status before the current frame |
4185
|
|
|
|
|
|
|
# was added. |
4186
|
|
|
|
|
|
|
|
4187
|
|
|
|
|
|
|
sub _frame_push { |
4188
|
59
|
|
|
59
|
|
164
|
my ( $self, $type, $args, $opt ) = @_; |
4189
|
59
|
|
50
|
|
|
167
|
$args ||= []; |
4190
|
59
|
|
100
|
|
|
254
|
$opt ||= {}; |
4191
|
59
|
|
100
|
|
|
103
|
my $frames = scalar @{$self->{frame} ||= []}; |
|
59
|
|
|
|
|
352
|
|
4192
|
59
|
100
|
|
|
|
202
|
my $prior = $frames ? $self->{frame}[-1] : { |
4193
|
|
|
|
|
|
|
condition => 1, |
4194
|
|
|
|
|
|
|
stdout => select(), |
4195
|
|
|
|
|
|
|
}; |
4196
|
|
|
|
|
|
|
my $condition = exists $opt->{condition} ? |
4197
|
|
|
|
|
|
|
$opt->{condition} : |
4198
|
59
|
100
|
|
|
|
162
|
$prior->{condition}; |
4199
|
|
|
|
|
|
|
#### defined $stdout or $stdout = select(); |
4200
|
59
|
|
|
|
|
203
|
my ( undef, $filename, $line ) = caller; |
4201
|
59
|
|
|
|
|
855
|
push @{$self->{frame}}, { |
4202
|
|
|
|
|
|
|
type => $type, |
4203
|
|
|
|
|
|
|
args => $args, |
4204
|
|
|
|
|
|
|
condition => $condition, |
4205
|
|
|
|
|
|
|
define => {}, # Macro defaults done with := |
4206
|
|
|
|
|
|
|
local => {}, |
4207
|
|
|
|
|
|
|
localout => undef, # Output for statement. |
4208
|
|
|
|
|
|
|
macro => {}, |
4209
|
|
|
|
|
|
|
pushed_by => "$filename line $line", |
4210
|
|
|
|
|
|
|
spacetrack => {}, |
4211
|
|
|
|
|
|
|
stdout => $prior->{localout} || $prior->{stdout}, |
4212
|
59
|
|
66
|
|
|
116
|
unsatisfied_if => $prior->{unsatisfied_if} || ! $condition, |
|
|
|
100
|
|
|
|
|
4213
|
|
|
|
|
|
|
}; |
4214
|
59
|
|
|
|
|
203
|
return $frames; |
4215
|
|
|
|
|
|
|
} |
4216
|
|
|
|
|
|
|
|
4217
|
|
|
|
|
|
|
# $satpass2->_frame_pop($frames); |
4218
|
|
|
|
|
|
|
# $satpass2->_frame_pop($type => $frames); |
4219
|
|
|
|
|
|
|
# $satpass2->_frame_pop(); |
4220
|
|
|
|
|
|
|
# |
4221
|
|
|
|
|
|
|
# This method pops context frames off the stack until there are |
4222
|
|
|
|
|
|
|
# $frames frames left. The optional $type argument is currently |
4223
|
|
|
|
|
|
|
# unused, but was intended for type checking should that become |
4224
|
|
|
|
|
|
|
# necessary. The zero-argument call pops one frame off the stack. |
4225
|
|
|
|
|
|
|
# An exception is thrown if there are no frames left to pop. After |
4226
|
|
|
|
|
|
|
# all required frames are popped, an exception is thrown if the |
4227
|
|
|
|
|
|
|
# pop was done with a continued input line pending. |
4228
|
|
|
|
|
|
|
|
4229
|
|
|
|
|
|
|
{ |
4230
|
|
|
|
|
|
|
|
4231
|
|
|
|
|
|
|
my %force_set; # If true, the named attribute is set with the |
4232
|
|
|
|
|
|
|
# set() method even if a hash key of the same |
4233
|
|
|
|
|
|
|
# name exists. This is set with |
4234
|
|
|
|
|
|
|
# _frame_pop_force_set(), typically where the |
4235
|
|
|
|
|
|
|
# mutator is defined. |
4236
|
|
|
|
|
|
|
|
4237
|
|
|
|
|
|
|
sub _frame_pop { |
4238
|
53
|
|
|
53
|
|
128
|
my ($self, @args) = @_; |
4239
|
|
|
|
|
|
|
## my $type = @args > 1 ? shift @args : undef; |
4240
|
53
|
100
|
|
|
|
150
|
@args > 1 and shift @args; # Currently unused |
4241
|
|
|
|
|
|
|
my $frames = ( @args && defined $args[0] ) ? |
4242
|
|
|
|
|
|
|
shift @args : |
4243
|
53
|
100
|
100
|
|
|
261
|
@{$self->{frame}} - 1; |
|
27
|
|
|
|
|
63
|
|
4244
|
53
|
|
|
|
|
96
|
while (@{$self->{frame}} > $frames) { |
|
105
|
|
|
|
|
284
|
|
4245
|
52
|
50
|
|
|
|
92
|
my $frame = pop @{$self->{frame}} |
|
52
|
|
|
|
|
172
|
|
4246
|
|
|
|
|
|
|
or $self->weep( 'No frame to pop' ); |
4247
|
52
|
|
50
|
|
|
146
|
my $local = $frame->{local} || {}; |
4248
|
52
|
|
|
|
|
127
|
foreach my $name ( keys %{ $local } ) { |
|
52
|
|
|
|
|
214
|
|
4249
|
2
|
|
|
|
|
19
|
my $value = $local->{$name}; |
4250
|
2
|
100
|
66
|
|
|
24
|
if ( exists $self->{$name} && !$force_set{$name} ) { |
4251
|
1
|
|
|
|
|
16
|
$self->{$name} = $value; |
4252
|
|
|
|
|
|
|
} else { |
4253
|
1
|
|
|
|
|
13
|
$self->set( $name, $value ); |
4254
|
|
|
|
|
|
|
} |
4255
|
|
|
|
|
|
|
} |
4256
|
52
|
|
|
|
|
118
|
foreach my $key (qw{macro}) { |
4257
|
52
|
|
50
|
|
|
201
|
my $info = $frame->{$key} || {}; |
4258
|
52
|
|
|
|
|
80
|
foreach my $name ( keys %{ $info } ) { |
|
52
|
|
|
|
|
147
|
|
4259
|
19
|
|
|
|
|
59
|
$self->{$key}{$name} = $info->{ $name }; |
4260
|
|
|
|
|
|
|
} |
4261
|
|
|
|
|
|
|
} |
4262
|
52
|
|
|
|
|
374
|
($frame->{spacetrack} && %{$frame->{spacetrack}}) |
4263
|
52
|
50
|
33
|
|
|
152
|
and $self->_get_spacetrack()->set(%{$frame->{spacetrack}}); |
|
0
|
|
|
|
|
0
|
|
4264
|
|
|
|
|
|
|
} |
4265
|
53
|
50
|
|
|
|
145
|
if (delete $self->{pending}) { |
4266
|
0
|
|
|
|
|
0
|
$self->wail('Input ended on continued line'); |
4267
|
|
|
|
|
|
|
} |
4268
|
53
|
|
|
|
|
135
|
return; |
4269
|
|
|
|
|
|
|
} |
4270
|
|
|
|
|
|
|
|
4271
|
|
|
|
|
|
|
# Force use of the set() method even if there is an attribute of the |
4272
|
|
|
|
|
|
|
# same name. |
4273
|
|
|
|
|
|
|
sub _frame_pop_force_set { |
4274
|
20
|
|
|
20
|
|
59
|
foreach my $name ( @_ ) { |
4275
|
20
|
|
|
|
|
65
|
$force_set{$name} = 1; |
4276
|
|
|
|
|
|
|
} |
4277
|
20
|
|
|
|
|
67
|
return; |
4278
|
|
|
|
|
|
|
} |
4279
|
|
|
|
|
|
|
} |
4280
|
|
|
|
|
|
|
|
4281
|
|
|
|
|
|
|
sub _get_browser_command { |
4282
|
0
|
|
|
0
|
|
0
|
my ( $self, $val ) = @_; |
4283
|
|
|
|
|
|
|
defined $val |
4284
|
0
|
0
|
|
|
|
0
|
or $val = $self->{webcmd}; |
4285
|
0
|
0
|
0
|
|
|
0
|
defined $val |
4286
|
|
|
|
|
|
|
and '' ne $val |
4287
|
|
|
|
|
|
|
or return $val; |
4288
|
0
|
0
|
|
|
|
0
|
'1' eq $val |
4289
|
|
|
|
|
|
|
or return $val; |
4290
|
0
|
|
|
|
|
0
|
require Browser::Open; |
4291
|
0
|
|
|
|
|
0
|
return Browser::Open::open_browser_cmd(); |
4292
|
|
|
|
|
|
|
} |
4293
|
|
|
|
|
|
|
|
4294
|
|
|
|
|
|
|
# $dumper = $self->_get_dumper(); |
4295
|
|
|
|
|
|
|
# |
4296
|
|
|
|
|
|
|
# This method returns a reference to code that can be used to dump |
4297
|
|
|
|
|
|
|
# data. The first time it is called it goes through a list of |
4298
|
|
|
|
|
|
|
# possible classes, and uses the first one it can load, dying if |
4299
|
|
|
|
|
|
|
# it can not load any of them. After the first successful call, it |
4300
|
|
|
|
|
|
|
# simply returns the cached dumper. |
4301
|
|
|
|
|
|
|
|
4302
|
|
|
|
|
|
|
{ |
4303
|
|
|
|
|
|
|
my $dumper; |
4304
|
|
|
|
|
|
|
my %kode = ( |
4305
|
|
|
|
|
|
|
'Data::Dumper' => sub { |
4306
|
|
|
|
|
|
|
local $Data::Dumper::Terse = 1; |
4307
|
|
|
|
|
|
|
Data::Dumper::Dumper(@_); |
4308
|
|
|
|
|
|
|
}, |
4309
|
|
|
|
|
|
|
); |
4310
|
|
|
|
|
|
|
sub _get_dumper { |
4311
|
0
|
|
|
0
|
|
0
|
my ($self) = @_; |
4312
|
0
|
|
|
|
|
0
|
my %dmpr; |
4313
|
|
|
|
|
|
|
my @mod; |
4314
|
0
|
|
0
|
|
|
0
|
return $dumper ||= do { |
4315
|
0
|
|
|
|
|
0
|
foreach (qw{YAML::Dump Data::Dumper::Dumper}) { |
4316
|
0
|
|
|
|
|
0
|
my ($module, $routine) = m/ (.*) :: (.*) /smx; |
4317
|
0
|
|
|
|
|
0
|
push @mod, $module; |
4318
|
0
|
|
|
|
|
0
|
$dmpr{$module} = $routine; |
4319
|
|
|
|
|
|
|
} |
4320
|
0
|
|
|
|
|
0
|
my $mod = $self->_load_module(@mod); |
4321
|
0
|
0
|
|
|
|
0
|
$kode{$mod} || $mod->can($dmpr{$mod}); |
4322
|
|
|
|
|
|
|
}; |
4323
|
|
|
|
|
|
|
} |
4324
|
|
|
|
|
|
|
} |
4325
|
|
|
|
|
|
|
|
4326
|
|
|
|
|
|
|
# $fmt = $satpass2->_get_dumper_object(); |
4327
|
|
|
|
|
|
|
# |
4328
|
|
|
|
|
|
|
# Gets a dumper object. This object must conform to the |
4329
|
|
|
|
|
|
|
# Astro::App::Satpass2::Format interface. |
4330
|
|
|
|
|
|
|
|
4331
|
|
|
|
|
|
|
{ |
4332
|
|
|
|
|
|
|
|
4333
|
|
|
|
|
|
|
my $dumper; |
4334
|
|
|
|
|
|
|
|
4335
|
|
|
|
|
|
|
sub _get_dumper_object { |
4336
|
0
|
|
0
|
0
|
|
0
|
return ( $dumper ||= do { |
4337
|
0
|
|
|
|
|
0
|
require Astro::App::Satpass2::Format::Dump; |
4338
|
0
|
|
|
|
|
0
|
Astro::App::Satpass2::Format::Dump->new(); |
4339
|
|
|
|
|
|
|
} |
4340
|
|
|
|
|
|
|
); |
4341
|
|
|
|
|
|
|
} |
4342
|
|
|
|
|
|
|
|
4343
|
|
|
|
|
|
|
} |
4344
|
|
|
|
|
|
|
|
4345
|
|
|
|
|
|
|
# $fmt = $satpass2->_get_formatter_object( $opt ); |
4346
|
|
|
|
|
|
|
# |
4347
|
|
|
|
|
|
|
# Gets the Astro::App::Satpass2::Format object. If $opt->{dump} is true, |
4348
|
|
|
|
|
|
|
# returns a dumper object; otherwise returns the currently-set |
4349
|
|
|
|
|
|
|
# formatter object. |
4350
|
|
|
|
|
|
|
|
4351
|
|
|
|
|
|
|
sub _get_formatter_object { |
4352
|
41
|
|
|
41
|
|
169
|
my ( $self, $opt ) = @_; |
4353
|
41
|
|
50
|
|
|
152
|
$opt ||= {}; |
4354
|
41
|
50
|
33
|
|
|
383
|
return ( $opt && $opt->{dump} ) ? $self->_get_dumper_object() : |
4355
|
|
|
|
|
|
|
$self->get( 'formatter' ); |
4356
|
|
|
|
|
|
|
} |
4357
|
|
|
|
|
|
|
|
4358
|
|
|
|
|
|
|
sub _get_formatter_attribute { |
4359
|
0
|
|
|
0
|
|
0
|
my ( $self, $name ) = @_; |
4360
|
0
|
|
|
|
|
0
|
return $self->get( 'formatter' )->$name(); |
4361
|
|
|
|
|
|
|
} |
4362
|
|
|
|
|
|
|
|
4363
|
|
|
|
|
|
|
# $st = $satpass2->_get_geocoder() |
4364
|
|
|
|
|
|
|
|
4365
|
|
|
|
|
|
|
# Gets the geocoder object, instantiating it if |
4366
|
|
|
|
|
|
|
# necesary. |
4367
|
|
|
|
|
|
|
|
4368
|
|
|
|
|
|
|
sub _get_geocoder { |
4369
|
0
|
|
|
0
|
|
0
|
my ( $self ) = @_; |
4370
|
0
|
0
|
|
|
|
0
|
if ( ! exists $self->{geocoder} ) { |
4371
|
0
|
|
|
|
|
0
|
my ( $class, $obj ); |
4372
|
0
|
0
|
|
|
|
0
|
$class = $default_geocoder->() |
4373
|
|
|
|
|
|
|
and $obj = $class->new(); |
4374
|
0
|
|
|
|
|
0
|
$self->{geocoder} = $obj; |
4375
|
|
|
|
|
|
|
} |
4376
|
0
|
|
|
|
|
0
|
return $self->{geocoder}; |
4377
|
|
|
|
|
|
|
} |
4378
|
|
|
|
|
|
|
|
4379
|
|
|
|
|
|
|
# $boolean = $satpass2->_get_interactive(); |
4380
|
|
|
|
|
|
|
# |
4381
|
|
|
|
|
|
|
# This method returns true if the script is running interactively, |
4382
|
|
|
|
|
|
|
# and false otherwise. Currently, it returns the results of -t |
4383
|
|
|
|
|
|
|
# STDIN. |
4384
|
|
|
|
|
|
|
|
4385
|
|
|
|
|
|
|
sub _get_interactive { |
4386
|
1
|
|
|
1
|
|
10
|
return -t STDIN; |
4387
|
|
|
|
|
|
|
} |
4388
|
|
|
|
|
|
|
|
4389
|
|
|
|
|
|
|
# $code = $satpass2->_get_readline(); |
4390
|
|
|
|
|
|
|
# |
4391
|
|
|
|
|
|
|
# Returns code to read input. The code takes an argument which |
4392
|
|
|
|
|
|
|
# will be used as a prompt if one is needed. What is actually |
4393
|
|
|
|
|
|
|
# returned is: |
4394
|
|
|
|
|
|
|
# |
4395
|
|
|
|
|
|
|
# If $satpass2->_get_interactive() is false, the returned code |
4396
|
|
|
|
|
|
|
# just reads standard in. Otherwise, |
4397
|
|
|
|
|
|
|
# |
4398
|
|
|
|
|
|
|
# if Term::ReadLine can be loaded, a Term::ReadLine object is |
4399
|
|
|
|
|
|
|
# instantiated if need be, and the returned code calls |
4400
|
|
|
|
|
|
|
# Term::ReadLine->readline($_[0]) and returns whatever that gives |
4401
|
|
|
|
|
|
|
# you. Otherwise, |
4402
|
|
|
|
|
|
|
# |
4403
|
|
|
|
|
|
|
# Otherwise the returned code writes its argument to STDERR and |
4404
|
|
|
|
|
|
|
# reads STDIN. |
4405
|
|
|
|
|
|
|
# |
4406
|
|
|
|
|
|
|
# Note that the return from this subroutine may or may not be |
4407
|
|
|
|
|
|
|
# chomped. |
4408
|
|
|
|
|
|
|
|
4409
|
|
|
|
|
|
|
my $readline_word_break_re; |
4410
|
|
|
|
|
|
|
|
4411
|
|
|
|
|
|
|
{ |
4412
|
|
|
|
|
|
|
my $rl; |
4413
|
|
|
|
|
|
|
|
4414
|
|
|
|
|
|
|
sub _get_readline { |
4415
|
1
|
|
|
1
|
|
7
|
my ($self) = @_; |
4416
|
|
|
|
|
|
|
# The Perl::Critic recommendation is IO::Interactive, but that |
4417
|
|
|
|
|
|
|
# fiddles with STDOUT. We want STDIN, because we want to behave |
4418
|
|
|
|
|
|
|
# differently if STDIN is a pipe, but not if STDOUT is a pipe. |
4419
|
|
|
|
|
|
|
# We're still missing the *ARGV logic, but that's OK too, since |
4420
|
|
|
|
|
|
|
# we use the contents of @ARGV as commands, not as file names. |
4421
|
1
|
|
|
|
|
2
|
return do { |
4422
|
1
|
|
|
|
|
3
|
my $buffer = ''; |
4423
|
1
|
50
|
|
|
|
4
|
if ($self->_get_interactive()) { |
4424
|
|
|
|
|
|
|
eval { |
4425
|
0
|
0
|
|
|
|
0
|
load_package( 'Term::ReadLine' ) |
4426
|
|
|
|
|
|
|
or return; |
4427
|
0
|
0
|
|
|
|
0
|
unless ( $rl ) { |
4428
|
0
|
|
|
|
|
0
|
$rl = Term::ReadLine->new( 'satpass2' ); |
4429
|
0
|
0
|
|
|
|
0
|
if ( 'Term::ReadLine::Perl' eq $rl->ReadLine() ) { |
4430
|
|
|
|
|
|
|
|
4431
|
0
|
|
0
|
|
|
0
|
$readline_word_break_re ||= qr< |
4432
|
|
|
|
|
|
|
[\Q$readline::rl_completer_word_break_characters\E]+ |
4433
|
|
|
|
|
|
|
>smx; |
4434
|
|
|
|
|
|
|
|
4435
|
20
|
|
|
20
|
|
100977
|
no warnings qw{ once }; |
|
20
|
|
|
|
|
65
|
|
|
20
|
|
|
|
|
16147
|
|
4436
|
|
|
|
|
|
|
$readline::rl_completion_function = sub { |
4437
|
0
|
|
|
0
|
|
0
|
my ( $text, $line, $start ) = @_; |
4438
|
0
|
|
|
|
|
0
|
return $self->__readline_completer( |
4439
|
|
|
|
|
|
|
$text, $line, $start ); |
4440
|
0
|
|
|
|
|
0
|
}; |
4441
|
|
|
|
|
|
|
} |
4442
|
|
|
|
|
|
|
} |
4443
|
|
|
|
|
|
|
sub { |
4444
|
0
|
0
|
|
0
|
|
0
|
defined $buffer or return $buffer; |
4445
|
0
|
|
|
|
|
0
|
return ( $buffer = $rl->readline($_[0]) ); |
4446
|
|
|
|
|
|
|
} |
4447
|
0
|
|
|
|
|
0
|
} || sub { |
4448
|
0
|
0
|
|
0
|
|
0
|
defined $buffer or return $buffer; |
4449
|
0
|
|
|
|
|
0
|
print STDERR $_[0]; |
4450
|
|
|
|
|
|
|
return ( |
4451
|
0
|
|
|
|
|
0
|
$buffer = ## no critic (ProhibitExplicitStdin) |
4452
|
|
|
|
|
|
|
); |
4453
|
0
|
0
|
|
|
|
0
|
}; |
4454
|
|
|
|
|
|
|
} else { |
4455
|
|
|
|
|
|
|
sub { |
4456
|
0
|
0
|
|
0
|
|
0
|
defined $buffer or return $buffer; |
4457
|
|
|
|
|
|
|
return ( |
4458
|
0
|
|
|
|
|
0
|
$buffer = ## no critic (ProhibitExplicitStdin) |
4459
|
|
|
|
|
|
|
); |
4460
|
1
|
|
|
|
|
7
|
}; |
4461
|
|
|
|
|
|
|
} |
4462
|
|
|
|
|
|
|
}; |
4463
|
|
|
|
|
|
|
} |
4464
|
|
|
|
|
|
|
} |
4465
|
|
|
|
|
|
|
|
4466
|
|
|
|
|
|
|
sub __readline_completer { |
4467
|
0
|
|
|
0
|
|
0
|
my ( $app, $text, $line, $start ) = @_; |
4468
|
|
|
|
|
|
|
|
4469
|
0
|
0
|
|
|
|
0
|
$start |
4470
|
|
|
|
|
|
|
or return $app->_readline_complete_command( $text ); |
4471
|
|
|
|
|
|
|
|
4472
|
0
|
|
|
|
|
0
|
my ( $cmd ) = split $readline_word_break_re, $line, 2; |
4473
|
0
|
|
|
|
|
0
|
my $code; |
4474
|
|
|
|
|
|
|
not $cmd =~ s/ \A core [.] //smx |
4475
|
|
|
|
|
|
|
and ref $app |
4476
|
|
|
|
|
|
|
and $app->{macro}{$cmd} |
4477
|
0
|
0
|
0
|
|
|
0
|
and $code = $app->{macro}{$cmd}->implements( $cmd ); |
|
|
|
0
|
|
|
|
|
4478
|
0
|
|
0
|
|
|
0
|
$code ||= $app->can( $cmd ); |
4479
|
|
|
|
|
|
|
|
4480
|
0
|
0
|
|
|
|
0
|
if ( CODE_REF eq ref $code ) { |
|
|
0
|
|
|
|
|
|
4481
|
|
|
|
|
|
|
# builtins and code macros go here |
4482
|
|
|
|
|
|
|
|
4483
|
0
|
|
|
|
|
0
|
my $rslt; |
4484
|
|
|
|
|
|
|
|
4485
|
0
|
0
|
|
|
|
0
|
if ( my $method = $app->__get_attr( $code, Tweak => {} |
4486
|
|
|
|
|
|
|
)->{completion} ) { |
4487
|
|
|
|
|
|
|
$rslt = $app->$method( $code, $text, $line, $start ) |
4488
|
0
|
0
|
|
|
|
0
|
and return @{ $rslt }; |
|
0
|
|
|
|
|
0
|
|
4489
|
|
|
|
|
|
|
} |
4490
|
|
|
|
|
|
|
|
4491
|
|
|
|
|
|
|
$rslt = $app->_readline_complete_options( $code, $text, |
4492
|
|
|
|
|
|
|
$line, $start ) |
4493
|
0
|
|
|
|
|
0
|
and @{ $rslt } |
4494
|
0
|
0
|
0
|
|
|
0
|
and return @{ $rslt }; |
|
0
|
|
|
|
|
0
|
|
4495
|
|
|
|
|
|
|
|
4496
|
|
|
|
|
|
|
} elsif ( my $macro = $app->{macro}{$cmd} ) { |
4497
|
|
|
|
|
|
|
# command macros go here |
4498
|
|
|
|
|
|
|
|
4499
|
0
|
|
|
|
|
0
|
my $rslt; |
4500
|
|
|
|
|
|
|
$rslt = $macro->completion( $text ) |
4501
|
0
|
0
|
|
|
|
0
|
and return @{ $rslt }; |
|
0
|
|
|
|
|
0
|
|
4502
|
|
|
|
|
|
|
} |
4503
|
|
|
|
|
|
|
|
4504
|
0
|
|
|
|
|
0
|
my @files = bsd_glob( "$text*" ); |
4505
|
0
|
0
|
|
|
|
0
|
if ( 1 == @files ) { |
|
|
0
|
|
|
|
|
|
4506
|
0
|
0
|
|
|
|
0
|
$files[0] .= -d $files[0] ? '/' : ' '; |
4507
|
|
|
|
|
|
|
} elsif ( $readline::var_CompleteAddsuffix ) { |
4508
|
0
|
|
|
|
|
0
|
foreach ( @files ) { |
4509
|
0
|
0
|
0
|
|
|
0
|
if ( -l $_ ) { |
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
4510
|
0
|
|
|
|
|
0
|
$_ .= '@'; |
4511
|
|
|
|
|
|
|
} elsif ( -d $_ ) { |
4512
|
0
|
|
|
|
|
0
|
$_ .= '/'; |
4513
|
|
|
|
|
|
|
} elsif ( -x _) { |
4514
|
0
|
|
|
|
|
0
|
$_ .= '*'; |
4515
|
|
|
|
|
|
|
} elsif ( -S _ || -p _ ) { |
4516
|
0
|
|
|
|
|
0
|
$_ .= '='; |
4517
|
|
|
|
|
|
|
} |
4518
|
|
|
|
|
|
|
} |
4519
|
|
|
|
|
|
|
} |
4520
|
0
|
|
|
|
|
0
|
$readline::rl_completer_terminator_character = ''; |
4521
|
0
|
|
|
|
|
0
|
return @files; |
4522
|
|
|
|
|
|
|
} |
4523
|
|
|
|
|
|
|
|
4524
|
|
|
|
|
|
|
{ |
4525
|
|
|
|
|
|
|
my @builtins; |
4526
|
|
|
|
|
|
|
sub _readline_complete_command { |
4527
|
0
|
|
|
0
|
|
0
|
my ( $app, $text ) = @_; |
4528
|
0
|
0
|
|
|
|
0
|
unless ( @builtins ) { |
4529
|
0
|
|
0
|
|
|
0
|
my $stash = ( ref $app || $app ) . '::'; |
4530
|
20
|
|
|
20
|
|
211
|
no strict qw{ refs }; |
|
20
|
|
|
|
|
49
|
|
|
20
|
|
|
|
|
15196
|
|
4531
|
0
|
|
|
|
|
0
|
foreach my $sym ( keys %$stash ) { |
4532
|
0
|
0
|
|
|
|
0
|
$sym =~ m/ \A _ /smx |
4533
|
|
|
|
|
|
|
and next; |
4534
|
0
|
0
|
|
|
|
0
|
my $code = $app->can( $sym ) |
4535
|
|
|
|
|
|
|
or next; |
4536
|
0
|
0
|
|
|
|
0
|
$app->__get_attr( $code, 'Verb' ) |
4537
|
|
|
|
|
|
|
or next; |
4538
|
0
|
|
|
|
|
0
|
push @builtins, $sym; |
4539
|
|
|
|
|
|
|
} |
4540
|
0
|
|
|
|
|
0
|
@builtins = sort @builtins; |
4541
|
|
|
|
|
|
|
} |
4542
|
0
|
|
|
|
|
0
|
my @rslt; |
4543
|
0
|
0
|
|
|
|
0
|
if ( $text =~ s/ \A core [.] //smx ) { |
4544
|
0
|
|
|
|
|
0
|
my $match = qr< \A \Q$text\E >smx; |
4545
|
0
|
|
|
|
|
0
|
@rslt = map { "core.$_" } grep { $_ =~ $match } @builtins; |
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
4546
|
|
|
|
|
|
|
} else { |
4547
|
0
|
|
|
|
|
0
|
my $match = qr< \A \Q$text\E >smx; |
4548
|
0
|
|
|
|
|
0
|
@rslt = grep { $_ =~ $match } @builtins, 'core.', |
4549
|
0
|
0
|
|
|
|
0
|
ref $app ? keys %{ $app->{macro} } : (); |
|
0
|
|
|
|
|
0
|
|
4550
|
|
|
|
|
|
|
} |
4551
|
0
|
0
|
0
|
|
|
0
|
1 == @rslt |
4552
|
|
|
|
|
|
|
and $rslt[0] =~ m/ \W \z /smx |
4553
|
|
|
|
|
|
|
and $readline::rl_completer_terminator_character = ''; |
4554
|
0
|
|
|
|
|
0
|
return ( sort @rslt ); |
4555
|
|
|
|
|
|
|
} |
4556
|
|
|
|
|
|
|
} |
4557
|
|
|
|
|
|
|
|
4558
|
|
|
|
|
|
|
sub _readline_complete_options { |
4559
|
|
|
|
|
|
|
# my ( $app, $code, $text, $line, $start ) = @_; |
4560
|
0
|
|
|
0
|
|
0
|
my ( $app, $code, $text ) = @_; |
4561
|
0
|
0
|
|
|
|
0
|
$text =~ m/ \A ( --? ) ( .* ) /smx |
4562
|
|
|
|
|
|
|
or return; |
4563
|
0
|
|
|
|
|
0
|
my ( $prefix, $match ) = ( $1, $2 ); |
4564
|
0
|
|
|
|
|
0
|
my $lgl = $app->__legal_options( $code ); |
4565
|
0
|
|
|
|
|
0
|
my $re = qr< \A \Q$match\E >smx; |
4566
|
0
|
|
|
|
|
0
|
my @rslt; |
4567
|
0
|
|
|
|
|
0
|
foreach ( @{ $lgl } ) { |
|
0
|
|
|
|
|
0
|
|
4568
|
0
|
0
|
|
|
|
0
|
next if ref; |
4569
|
|
|
|
|
|
|
# De-alias before modifying |
4570
|
0
|
|
|
|
|
0
|
( my $o = $_ ) =~ s/ [!=?] .* //smx; |
4571
|
0
|
|
|
|
|
0
|
push @rslt, grep { m/$re/ } split qr< \| >smx, $o; |
|
0
|
|
|
|
|
0
|
|
4572
|
|
|
|
|
|
|
} |
4573
|
|
|
|
|
|
|
@rslt |
4574
|
0
|
0
|
|
|
|
0
|
and return [ map { "$prefix$_" } sort @rslt ]; |
|
0
|
|
|
|
|
0
|
|
4575
|
0
|
|
|
|
|
0
|
return; |
4576
|
|
|
|
|
|
|
} |
4577
|
|
|
|
|
|
|
|
4578
|
|
|
|
|
|
|
# The following subroutine is called dynamically |
4579
|
|
|
|
|
|
|
sub _readline_complete_subcommand { ## no critic (ProhibitUnusedPrivateSubroutines) |
4580
|
|
|
|
|
|
|
# my ( $app, $code, $text, $line, $start ) = @_; |
4581
|
0
|
|
|
0
|
|
0
|
my ( $app, undef, $text, $line, $start ) = @_; |
4582
|
0
|
|
|
|
|
0
|
my @part = _readline_line_to_parts( $line ); |
4583
|
0
|
0
|
|
|
|
0
|
if ( my $code = $app->can( "_$part[0]_sub" ) ) { |
4584
|
0
|
|
|
|
|
0
|
return $code->( $app, $text, $line, $start, @part ); |
4585
|
|
|
|
|
|
|
} |
4586
|
0
|
|
|
|
|
0
|
my @rslt; |
4587
|
0
|
0
|
|
|
|
0
|
if ( 2 == @part ) { |
4588
|
0
|
|
|
|
|
0
|
my $re = qr< \A _$part[0]_sub_ ( \Q$part[1]\E \w* ) >smx; |
4589
|
0
|
|
0
|
|
|
0
|
my $stash = ( ref $app || $app ) . '::'; |
4590
|
20
|
|
|
20
|
|
170
|
no strict qw{ refs }; |
|
20
|
|
|
|
|
53
|
|
|
20
|
|
|
|
|
33217
|
|
4591
|
0
|
|
|
|
|
0
|
foreach my $key ( keys %$stash ) { |
4592
|
0
|
0
|
|
|
|
0
|
$key =~ m/$re/smx |
4593
|
|
|
|
|
|
|
and push @rslt, "$1"; |
4594
|
|
|
|
|
|
|
} |
4595
|
0
|
|
|
|
|
0
|
return [ sort @rslt ]; |
4596
|
|
|
|
|
|
|
} |
4597
|
|
|
|
|
|
|
|
4598
|
0
|
0
|
|
|
|
0
|
my $code = $app->can( "_$part[0]_sub_$part[1]" ) |
4599
|
|
|
|
|
|
|
or return; |
4600
|
|
|
|
|
|
|
|
4601
|
0
|
|
|
|
|
0
|
my $r; |
4602
|
0
|
0
|
|
|
|
0
|
$r = $app->_readline_complete_options( $code, $text, $line, |
4603
|
|
|
|
|
|
|
$start ) |
4604
|
|
|
|
|
|
|
and return $r; |
4605
|
|
|
|
|
|
|
|
4606
|
|
|
|
|
|
|
my $complete = $app->__get_attr( $code, Tweak => {} )->{completion} |
4607
|
0
|
0
|
|
|
|
0
|
or return; |
4608
|
|
|
|
|
|
|
|
4609
|
0
|
0
|
|
|
|
0
|
$r = $app->$complete( $code, $text, $line, $start ) |
4610
|
|
|
|
|
|
|
and return $r; |
4611
|
|
|
|
|
|
|
|
4612
|
0
|
|
|
|
|
0
|
return; |
4613
|
|
|
|
|
|
|
} |
4614
|
|
|
|
|
|
|
|
4615
|
|
|
|
|
|
|
sub _macro_list_complete { ## no critic (ProhibitUnusedPrivateSubroutines) |
4616
|
|
|
|
|
|
|
# my ( $app, $code, $text, $line, $start ) = @_; |
4617
|
0
|
|
|
0
|
|
0
|
my ( $app, undef, undef, $line, undef ) = @_; |
4618
|
0
|
0
|
|
|
|
0
|
ref $app |
4619
|
|
|
|
|
|
|
or return; |
4620
|
0
|
|
|
|
|
0
|
my @part = _readline_line_to_parts( $line ); |
4621
|
0
|
0
|
|
|
|
0
|
3 == @part |
4622
|
|
|
|
|
|
|
or return; |
4623
|
0
|
|
|
|
|
0
|
my $re = qr< \A \Q$part[2]\E >smx; |
4624
|
0
|
|
|
|
|
0
|
my @rslt; |
4625
|
0
|
|
|
|
|
0
|
foreach ( sort keys %{ $app->{macro} } ) { |
|
0
|
|
|
|
|
0
|
|
4626
|
0
|
0
|
|
|
|
0
|
m/$re/smx |
4627
|
|
|
|
|
|
|
and push @rslt, $_; |
4628
|
|
|
|
|
|
|
} |
4629
|
0
|
|
|
|
|
0
|
return \@rslt; |
4630
|
|
|
|
|
|
|
} |
4631
|
|
|
|
|
|
|
|
4632
|
|
|
|
|
|
|
sub _sky_body_complete { ## no critic (ProhibitUnusedPrivateSubroutines) |
4633
|
|
|
|
|
|
|
# my ( $app, $code, $text, $line, $start ) = @_; |
4634
|
0
|
|
|
0
|
|
0
|
my ( $app, undef, undef, $line, undef ) = @_; |
4635
|
0
|
0
|
|
|
|
0
|
ref $app |
4636
|
|
|
|
|
|
|
or return; |
4637
|
0
|
|
|
|
|
0
|
my @part = _readline_line_to_parts( $line ); |
4638
|
0
|
0
|
|
|
|
0
|
3 == @part |
4639
|
|
|
|
|
|
|
or return; |
4640
|
0
|
|
|
|
|
0
|
my $re = qr< \A \Q$part[2]\E >smxi; |
4641
|
0
|
|
|
|
|
0
|
my @rslt; |
4642
|
0
|
|
|
|
|
0
|
foreach my $body ( @{ $app->{sky} } ) { |
|
0
|
|
|
|
|
0
|
|
4643
|
0
|
0
|
|
|
|
0
|
if ( ( my $name = $body->get( 'name' ) ) =~ $re ) { |
|
|
0
|
|
|
|
|
|
4644
|
0
|
|
|
|
|
0
|
push @rslt, $name; |
4645
|
|
|
|
|
|
|
} elsif ( ( my $id = $body->get( 'id' ) ) =~ $re ) { |
4646
|
0
|
|
|
|
|
0
|
push @rslt, $id; |
4647
|
|
|
|
|
|
|
} |
4648
|
|
|
|
|
|
|
} |
4649
|
0
|
|
|
|
|
0
|
return [ sort @rslt ]; |
4650
|
|
|
|
|
|
|
} |
4651
|
|
|
|
|
|
|
|
4652
|
|
|
|
|
|
|
sub _readline_line_to_parts { |
4653
|
0
|
|
|
0
|
|
0
|
my ( $line ) = @_; |
4654
|
|
|
|
|
|
|
# NOTE that the field count of -1 causes a trailing separator to |
4655
|
|
|
|
|
|
|
# result in a trailing empty field. |
4656
|
0
|
|
|
|
|
0
|
my @parts = split $readline_word_break_re, $line, -1; |
4657
|
|
|
|
|
|
|
# NOTE that we strip the leading 'core.' if any, so the return from |
4658
|
|
|
|
|
|
|
# this method does not distinguish between a core command and the |
4659
|
|
|
|
|
|
|
# same-named macro if any. |
4660
|
|
|
|
|
|
|
@parts |
4661
|
0
|
0
|
|
|
|
0
|
and $parts[0] =~ s/ \A core [.] //smx; |
4662
|
0
|
|
|
|
|
0
|
return @parts; |
4663
|
|
|
|
|
|
|
} |
4664
|
|
|
|
|
|
|
|
4665
|
|
|
|
|
|
|
sub _get_time_parser_attribute { |
4666
|
0
|
|
|
0
|
|
0
|
my ( $self, $name ) = @_; |
4667
|
0
|
|
|
|
|
0
|
return $self->{time_parser}->$name(); |
4668
|
|
|
|
|
|
|
} |
4669
|
|
|
|
|
|
|
|
4670
|
|
|
|
|
|
|
# $st = $satpass2->_get_spacetrack() |
4671
|
|
|
|
|
|
|
|
4672
|
|
|
|
|
|
|
# Gets the Astro::SpaceTrack object, instantiating it if |
4673
|
|
|
|
|
|
|
# necesary. |
4674
|
|
|
|
|
|
|
|
4675
|
|
|
|
|
|
|
sub _get_spacetrack { |
4676
|
7
|
|
|
7
|
|
21
|
my ( $self ) = @_; |
4677
|
|
|
|
|
|
|
exists $self->{spacetrack} |
4678
|
7
|
50
|
|
|
|
62
|
or $self->{spacetrack} = $self->_get_spacetrack_default(); |
4679
|
7
|
|
|
|
|
32
|
return $self->{spacetrack}; |
4680
|
|
|
|
|
|
|
} |
4681
|
|
|
|
|
|
|
|
4682
|
|
|
|
|
|
|
# $st = $satpass2->_get_spacetrack_default(); |
4683
|
|
|
|
|
|
|
# |
4684
|
|
|
|
|
|
|
# Returns a new Astro::SpaceTrack object, initialized with this |
4685
|
|
|
|
|
|
|
# object's webcmd, and with its filter attribute set to 1 and its |
4686
|
|
|
|
|
|
|
# iridium_status_format set to 'kelso'. |
4687
|
|
|
|
|
|
|
|
4688
|
|
|
|
|
|
|
sub _get_spacetrack_default { |
4689
|
7
|
|
|
7
|
|
37
|
my ( $self ) = @_; |
4690
|
7
|
50
|
|
|
|
31
|
$have_astro_spacetrack->() |
4691
|
|
|
|
|
|
|
or return; |
4692
|
|
|
|
|
|
|
return Astro::SpaceTrack->new ( |
4693
|
|
|
|
|
|
|
webcmd => $self->{webcmd}, |
4694
|
0
|
|
|
|
|
0
|
filter => 1, |
4695
|
|
|
|
|
|
|
iridium_status_format => 'kelso', |
4696
|
|
|
|
|
|
|
); |
4697
|
|
|
|
|
|
|
} |
4698
|
|
|
|
|
|
|
|
4699
|
|
|
|
|
|
|
sub _get_day_midnight { |
4700
|
10
|
|
|
10
|
|
42
|
my ( $self, $day ) = @_; |
4701
|
10
|
100
|
|
|
|
44
|
defined $day |
4702
|
|
|
|
|
|
|
or $day = time; |
4703
|
10
|
|
|
|
|
38
|
my $gmt = $self->get( 'formatter' )->gmt(); |
4704
|
10
|
50
|
|
|
|
108
|
my @time = $gmt ? gmtime( $day ) : localtime( $day ); |
4705
|
10
|
|
|
|
|
33
|
$time[0] = $time[1] = $time[2] = 0; |
4706
|
10
|
|
|
|
|
26
|
$time[5] += 1900; |
4707
|
10
|
50
|
|
|
|
64
|
return $gmt ? greg_time_gm(@time) : greg_time_local(@time); |
4708
|
|
|
|
|
|
|
} |
4709
|
|
|
|
|
|
|
|
4710
|
|
|
|
|
|
|
sub _get_day_noon { |
4711
|
42
|
|
|
42
|
|
114
|
my ( $self, $day ) = @_; |
4712
|
42
|
100
|
|
|
|
135
|
defined $day |
4713
|
|
|
|
|
|
|
or $day = time; |
4714
|
42
|
|
|
|
|
143
|
my $gmt = $self->get( 'formatter' )->gmt(); |
4715
|
42
|
50
|
|
|
|
339
|
my @time = $gmt ? gmtime( $day ) : localtime( $day ); |
4716
|
42
|
|
|
|
|
117
|
$time[0] = $time[1] = 0; |
4717
|
42
|
|
|
|
|
80
|
$time[2] = 12; |
4718
|
42
|
|
|
|
|
113
|
$time[5] += 1900; |
4719
|
42
|
50
|
|
|
|
218
|
return $gmt ? greg_time_gm(@time) : greg_time_local(@time); |
4720
|
|
|
|
|
|
|
} |
4721
|
|
|
|
|
|
|
|
4722
|
|
|
|
|
|
|
sub _get_warner_attribute { |
4723
|
0
|
|
|
0
|
|
0
|
my ( $self, $name ) = @_; |
4724
|
0
|
|
|
|
|
0
|
return $self->{_warner}->$name(); |
4725
|
|
|
|
|
|
|
} |
4726
|
|
|
|
|
|
|
|
4727
|
|
|
|
|
|
|
sub _helper_get_object { |
4728
|
9
|
|
|
9
|
|
20
|
my ( $self, $attribute ) = @_; |
4729
|
9
|
50
|
|
|
|
22
|
my $object = $self->get( $attribute ) |
4730
|
|
|
|
|
|
|
or $self->wail( "No $attribute object available" ); |
4731
|
9
|
|
|
|
|
22
|
return $object; |
4732
|
|
|
|
|
|
|
} |
4733
|
|
|
|
|
|
|
|
4734
|
|
|
|
|
|
|
{ |
4735
|
|
|
|
|
|
|
|
4736
|
|
|
|
|
|
|
my %parse_input = ( |
4737
|
|
|
|
|
|
|
formatter => { |
4738
|
|
|
|
|
|
|
desired_equinox_dynamical => sub { |
4739
|
|
|
|
|
|
|
my ( $self, undef, @args ) = @_; # $opt unused |
4740
|
|
|
|
|
|
|
if ( $args[0] ) { |
4741
|
|
|
|
|
|
|
$args[0] = $self->__parse_time( $args[0], 0 ); |
4742
|
|
|
|
|
|
|
} |
4743
|
|
|
|
|
|
|
return @args; |
4744
|
|
|
|
|
|
|
}, |
4745
|
|
|
|
|
|
|
format => sub { |
4746
|
|
|
|
|
|
|
my ( $self, $opt, $template, @args ) = @_; |
4747
|
|
|
|
|
|
|
$opt->{raw} = 1; |
4748
|
|
|
|
|
|
|
return ( |
4749
|
|
|
|
|
|
|
arg => \@args, |
4750
|
|
|
|
|
|
|
sp => $self, |
4751
|
|
|
|
|
|
|
template => $template, |
4752
|
|
|
|
|
|
|
); |
4753
|
|
|
|
|
|
|
}, |
4754
|
|
|
|
|
|
|
}, |
4755
|
|
|
|
|
|
|
time_parser => { |
4756
|
|
|
|
|
|
|
base => sub { |
4757
|
|
|
|
|
|
|
my ( $self, undef, @args ) = @_; # $opt unused |
4758
|
|
|
|
|
|
|
if ( @args && defined $args[0] ) { |
4759
|
|
|
|
|
|
|
$args[0] = $self->__parse_time( $args[0], time ); |
4760
|
|
|
|
|
|
|
} |
4761
|
|
|
|
|
|
|
return @args; |
4762
|
|
|
|
|
|
|
} |
4763
|
|
|
|
|
|
|
}, |
4764
|
|
|
|
|
|
|
); |
4765
|
|
|
|
|
|
|
|
4766
|
|
|
|
|
|
|
sub _helper_handler : Verb( changes! raw! ) { |
4767
|
9
|
|
|
9
|
|
34
|
my ( $self, $opt, $name, $method, @args ) = __arguments( @_ ); |
4768
|
|
|
|
|
|
|
|
4769
|
|
|
|
|
|
|
exists $opt->{raw} |
4770
|
9
|
50
|
|
|
|
47
|
or $opt->{raw} = ( ! _is_interactive() ); |
4771
|
|
|
|
|
|
|
|
4772
|
9
|
50
|
|
|
|
35
|
defined $method |
4773
|
|
|
|
|
|
|
or $self->wail( 'No method name specified' ); |
4774
|
|
|
|
|
|
|
|
4775
|
9
|
50
|
|
|
|
42
|
'config' eq $method |
4776
|
|
|
|
|
|
|
and return $self->_helper_config_handler( $name => $opt ); |
4777
|
|
|
|
|
|
|
|
4778
|
9
|
|
|
|
|
34
|
my $object = $self->_helper_get_object( $name ); |
4779
|
9
|
50
|
33
|
|
|
76
|
$method !~ m/ \A _ /smx and $object->can( $method ) |
4780
|
|
|
|
|
|
|
or $self->wail("No such $name method as '$method'"); |
4781
|
|
|
|
|
|
|
|
4782
|
|
|
|
|
|
|
@args |
4783
|
|
|
|
|
|
|
and $parse_input{$name} |
4784
|
|
|
|
|
|
|
and $parse_input{$name}{$method} |
4785
|
9
|
100
|
66
|
|
|
73
|
and @args = $parse_input{$name}{$method}->( $self, $opt, @args ); |
|
|
|
66
|
|
|
|
|
4786
|
|
|
|
|
|
|
delete $opt->{raw} |
4787
|
9
|
100
|
|
|
|
45
|
and return $object->$method( @args ); |
4788
|
5
|
|
|
|
|
21
|
my @rslt = $object->decode( $method, @args ); |
4789
|
|
|
|
|
|
|
|
4790
|
5
|
100
|
|
|
|
83
|
instance( $rslt[0], ref $object ) and return; |
4791
|
2
|
50
|
|
|
|
7
|
ref $rslt[0] and return $rslt[0]; |
4792
|
2
|
|
|
|
|
7
|
return quoter( $name, $method, @rslt ) . "\n"; |
4793
|
20
|
|
|
20
|
|
195
|
} |
|
20
|
|
|
|
|
69
|
|
|
20
|
|
|
|
|
130
|
|
4794
|
|
|
|
|
|
|
} |
4795
|
|
|
|
|
|
|
|
4796
|
|
|
|
|
|
|
sub _helper_config_handler { |
4797
|
0
|
|
|
0
|
|
0
|
my ( $self, $name, $opt ) = @_; |
4798
|
0
|
|
|
|
|
0
|
my $object = $self->_helper_get_object( $name ); |
4799
|
|
|
|
|
|
|
my $rslt = $object->config( |
4800
|
|
|
|
|
|
|
changes => $opt->{changes}, |
4801
|
|
|
|
|
|
|
decode => ! $opt->{raw}, |
4802
|
0
|
|
|
|
|
0
|
); |
4803
|
0
|
0
|
|
|
|
0
|
$opt->{raw} and return $rslt; |
4804
|
0
|
|
|
|
|
0
|
my $output = ''; |
4805
|
0
|
|
|
|
|
0
|
foreach my $item ( @{ $rslt } ) { |
|
0
|
|
|
|
|
0
|
|
4806
|
0
|
|
|
|
|
0
|
$output .= quoter( $name, @{ $item } ) . "\n"; |
|
0
|
|
|
|
|
0
|
|
4807
|
|
|
|
|
|
|
} |
4808
|
0
|
|
|
|
|
0
|
return $output; |
4809
|
|
|
|
|
|
|
} |
4810
|
|
|
|
|
|
|
|
4811
|
|
|
|
|
|
|
# $satpass2->_iridium_status(\@status) |
4812
|
|
|
|
|
|
|
|
4813
|
|
|
|
|
|
|
# Updates the status of all Iridium satellites from the given |
4814
|
|
|
|
|
|
|
# array, which is compatible with the second item returned by |
4815
|
|
|
|
|
|
|
# Astro::SpaceTrack->iridium_status(). If no argument is passed, |
4816
|
|
|
|
|
|
|
# the status is retrieved using Astro::SpaceTrack->iridium_status() |
4817
|
|
|
|
|
|
|
|
4818
|
|
|
|
|
|
|
sub _iridium_status { |
4819
|
0
|
|
|
0
|
|
0
|
my ($self, $status) = @_; |
4820
|
0
|
0
|
|
|
|
0
|
unless ($status) { |
4821
|
0
|
|
|
|
|
0
|
my $st = $self->_get_spacetrack(); |
4822
|
0
|
|
|
|
|
0
|
(my $rslt, $status) = $st->iridium_status; |
4823
|
0
|
0
|
|
|
|
0
|
$rslt->is_success or $self->wail($rslt->status_line); |
4824
|
|
|
|
|
|
|
} |
4825
|
|
|
|
|
|
|
|
4826
|
0
|
0
|
|
|
|
0
|
if ( ARRAY_REF eq ref $status ) { |
4827
|
0
|
|
|
|
|
0
|
Astro::Coord::ECI::TLE->status (clear => 'iridium'); |
4828
|
0
|
|
|
|
|
0
|
foreach (@$status) { |
4829
|
0
|
|
|
|
|
0
|
Astro::Coord::ECI::TLE->status (add => $_->[0], iridium => |
4830
|
|
|
|
|
|
|
$_->[4], $_->[1], $_->[3]); |
4831
|
|
|
|
|
|
|
} |
4832
|
|
|
|
|
|
|
} else { |
4833
|
0
|
|
|
|
|
0
|
$self->weep( |
4834
|
|
|
|
|
|
|
'Portable status not passed, and unavailable from Astro::SpaceTrack' |
4835
|
|
|
|
|
|
|
); |
4836
|
|
|
|
|
|
|
} |
4837
|
|
|
|
|
|
|
|
4838
|
0
|
|
|
|
|
0
|
foreach my $tle (@{$self->{bodies}}) { |
|
0
|
|
|
|
|
0
|
|
4839
|
0
|
|
|
|
|
0
|
$tle->rebless (); |
4840
|
|
|
|
|
|
|
} |
4841
|
|
|
|
|
|
|
|
4842
|
0
|
|
|
|
|
0
|
return; |
4843
|
|
|
|
|
|
|
|
4844
|
|
|
|
|
|
|
} |
4845
|
|
|
|
|
|
|
|
4846
|
|
|
|
|
|
|
# _is_case_tolerant() |
4847
|
|
|
|
|
|
|
# Returns true if the OS supports case-tolerant file names. Yes, I know |
4848
|
|
|
|
|
|
|
# it's the file system that is important, but I don't have access to |
4849
|
|
|
|
|
|
|
# that level of detail. |
4850
|
|
|
|
|
|
|
{ |
4851
|
|
|
|
|
|
|
my %os = map { $_ => 1 } qw{ darwin }; |
4852
|
|
|
|
|
|
|
|
4853
|
|
|
|
|
|
|
sub _is_case_tolerant { |
4854
|
|
|
|
|
|
|
exists $os{$^O} |
4855
|
0
|
0
|
|
0
|
|
0
|
and return $os{$^O}; |
4856
|
0
|
|
|
|
|
0
|
return File::Spec->case_tolerant(); |
4857
|
|
|
|
|
|
|
} |
4858
|
|
|
|
|
|
|
} |
4859
|
|
|
|
|
|
|
|
4860
|
|
|
|
|
|
|
# _is_interactive() |
4861
|
|
|
|
|
|
|
# |
4862
|
|
|
|
|
|
|
# Returns true if the dispatch() method is above us on the call |
4863
|
|
|
|
|
|
|
# stack, otherwise returns false. |
4864
|
|
|
|
|
|
|
|
4865
|
20
|
|
|
20
|
|
12957
|
use constant INTERACTIVE_CALLER => __PACKAGE__ . '::dispatch'; |
|
20
|
|
|
|
|
68
|
|
|
20
|
|
|
|
|
3044
|
|
4866
|
|
|
|
|
|
|
sub _is_interactive { |
4867
|
364
|
|
|
364
|
|
622
|
my $level = 0; |
4868
|
364
|
|
|
|
|
2179
|
while ( my @info = caller( $level ) ) { |
4869
|
1520
|
100
|
|
|
|
3159
|
INTERACTIVE_CALLER eq $info[3] |
4870
|
|
|
|
|
|
|
and return $level; |
4871
|
1482
|
|
|
|
|
6174
|
$level++; |
4872
|
|
|
|
|
|
|
} |
4873
|
326
|
|
|
|
|
684
|
return; |
4874
|
|
|
|
|
|
|
} |
4875
|
|
|
|
|
|
|
|
4876
|
|
|
|
|
|
|
# $self->_load_module ($module_name) |
4877
|
|
|
|
|
|
|
|
4878
|
|
|
|
|
|
|
# Loads the module if it has not yet been loaded. Dies if it |
4879
|
|
|
|
|
|
|
# can not be loaded. |
4880
|
|
|
|
|
|
|
|
4881
|
|
|
|
|
|
|
{ # Begin local symbol block |
4882
|
|
|
|
|
|
|
|
4883
|
|
|
|
|
|
|
my %version; |
4884
|
|
|
|
|
|
|
BEGIN { |
4885
|
20
|
|
|
20
|
|
128970
|
%version = ( |
4886
|
|
|
|
|
|
|
'Astro::SpaceTrack' => ASTRO_SPACETRACK_VERSION, |
4887
|
|
|
|
|
|
|
); |
4888
|
|
|
|
|
|
|
} |
4889
|
|
|
|
|
|
|
|
4890
|
|
|
|
|
|
|
sub _load_module { |
4891
|
0
|
|
|
0
|
|
0
|
my ($self, @module) = @_; |
4892
|
|
|
|
|
|
|
ARRAY_REF eq ref $module[0] |
4893
|
0
|
0
|
|
|
|
0
|
and @module = @{$module[0]}; |
|
0
|
|
|
|
|
0
|
|
4894
|
0
|
0
|
|
|
|
0
|
@module or $self->weep( 'No module specified' ); |
4895
|
0
|
|
|
|
|
0
|
my @probs; |
4896
|
0
|
|
|
|
|
0
|
foreach my $module (@module) { |
4897
|
0
|
0
|
|
|
|
0
|
load_package ($module) or do { |
4898
|
0
|
|
|
|
|
0
|
push @probs, "$module needed"; |
4899
|
0
|
|
|
|
|
0
|
next; |
4900
|
|
|
|
|
|
|
}; |
4901
|
0
|
|
|
|
|
0
|
my $modver; |
4902
|
0
|
0
|
0
|
|
|
0
|
($version{$module} && ($modver = $module->VERSION)) and do { |
4903
|
0
|
|
|
|
|
0
|
$modver =~ s/_//g; |
4904
|
0
|
0
|
|
|
|
0
|
$modver < $version{$module} and do { |
4905
|
0
|
|
|
|
|
0
|
push @probs, |
4906
|
|
|
|
|
|
|
"$module version $version{$module} needed"; |
4907
|
0
|
|
|
|
|
0
|
next; |
4908
|
|
|
|
|
|
|
}; |
4909
|
|
|
|
|
|
|
}; |
4910
|
0
|
|
|
|
|
0
|
return $module; |
4911
|
|
|
|
|
|
|
} |
4912
|
|
|
|
|
|
|
{ |
4913
|
0
|
|
|
|
|
0
|
my $inx = 1; |
|
0
|
|
|
|
|
0
|
|
4914
|
0
|
|
|
|
|
0
|
while (my @clr = caller($inx++)) { |
4915
|
0
|
0
|
|
|
|
0
|
$clr[3] eq '(eval)' and next; |
4916
|
0
|
|
|
|
|
0
|
my @raw = split '::', $clr[3]; |
4917
|
0
|
0
|
|
|
|
0
|
substr ($raw[-1], 0, 1) eq '_' and next; |
4918
|
0
|
|
|
|
|
0
|
push @probs, "for method $raw[-1]"; |
4919
|
0
|
|
|
|
|
0
|
last; |
4920
|
|
|
|
|
|
|
} |
4921
|
|
|
|
|
|
|
} |
4922
|
0
|
|
|
|
|
0
|
my $pfx = 'Error -'; |
4923
|
0
|
|
|
|
|
0
|
$self->wail(map {my $x = "$pfx $_\n"; $pfx = ' ' x 7; $x} @probs); |
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
4924
|
0
|
|
|
|
|
0
|
return; # Can't get here, but Perl::Critic does not know this. |
4925
|
|
|
|
|
|
|
} |
4926
|
|
|
|
|
|
|
|
4927
|
|
|
|
|
|
|
} # end local symbol block. |
4928
|
|
|
|
|
|
|
|
4929
|
|
|
|
|
|
|
# $output = $self->_macro($name,@args) |
4930
|
|
|
|
|
|
|
# |
4931
|
|
|
|
|
|
|
# Execute the named macro. The @args are of course optional. |
4932
|
|
|
|
|
|
|
|
4933
|
|
|
|
|
|
|
sub _macro { |
4934
|
19
|
|
|
19
|
|
42
|
my ($self, $name, @args) = @_; |
4935
|
19
|
50
|
|
|
|
43
|
$self->{macro}{$name} or $self->wail("No such macro as '$name'"); |
4936
|
19
|
|
|
|
|
55
|
my $frames = $self->_frame_push(macro => [@args]); |
4937
|
|
|
|
|
|
|
my $macro = $self->{frame}[-1]{macro}{$name} = |
4938
|
19
|
|
|
|
|
65
|
delete $self->{macro}{$name}; |
4939
|
19
|
|
|
|
|
33
|
my $output; |
4940
|
|
|
|
|
|
|
my $err; |
4941
|
19
|
100
|
|
|
|
39
|
my $ok = eval { |
4942
|
19
|
|
|
|
|
71
|
$output = $macro->execute( $name, @args ); |
4943
|
18
|
|
|
|
|
43
|
1; |
4944
|
|
|
|
|
|
|
} or $err = $@; |
4945
|
19
|
|
|
|
|
92
|
$self->_frame_pop($frames); |
4946
|
19
|
100
|
|
|
|
43
|
$ok or $self->wail($err); |
4947
|
18
|
|
|
|
|
69
|
return $output; |
4948
|
|
|
|
|
|
|
} |
4949
|
|
|
|
|
|
|
|
4950
|
|
|
|
|
|
|
# $angle = _parse_angle_parts ( @parts ); |
4951
|
|
|
|
|
|
|
# |
4952
|
|
|
|
|
|
|
# Joins parts of angles into an angle. |
4953
|
|
|
|
|
|
|
# The @parts array is array references describing the parts in |
4954
|
|
|
|
|
|
|
# decreasing significance, with [0] being the value, and [1] being |
4955
|
|
|
|
|
|
|
# the number in the next larger part. For the first piece, [1] |
4956
|
|
|
|
|
|
|
# should be the number in an entire circle. |
4957
|
|
|
|
|
|
|
|
4958
|
|
|
|
|
|
|
sub _parse_angle_parts { |
4959
|
3
|
|
|
3
|
|
9
|
my @parts = @_; |
4960
|
3
|
|
|
|
|
7
|
my $angle = 0; |
4961
|
3
|
|
|
|
|
7
|
my $circle = 1; |
4962
|
3
|
|
|
|
|
6
|
my $places; |
4963
|
3
|
|
|
|
|
7
|
foreach ( @parts ) { |
4964
|
9
|
|
|
|
|
15
|
my ( $part, $size ) = @{ $_ }; |
|
9
|
|
|
|
|
22
|
|
4965
|
9
|
50
|
|
|
|
22
|
defined $part or last; |
4966
|
9
|
|
|
|
|
14
|
$circle *= $size; |
4967
|
9
|
|
|
|
|
18
|
$angle = $angle * $size + $part; |
4968
|
9
|
50
|
|
|
|
24
|
$places = $part =~ m/ [.] ( [0-9]+ ) /smx ? length $1 : 0; |
4969
|
|
|
|
|
|
|
} |
4970
|
3
|
|
|
|
|
10
|
$angle *= 360 / $circle; |
4971
|
3
|
50
|
|
|
|
17
|
if ( my $mag = sprintf '%d', $circle / 360 ) { |
4972
|
3
|
|
|
|
|
8
|
$places += length $mag; |
4973
|
|
|
|
|
|
|
} |
4974
|
3
|
|
|
|
|
51
|
return sprintf( '%.*f', $places, $angle ) + 0; |
4975
|
|
|
|
|
|
|
} |
4976
|
|
|
|
|
|
|
|
4977
|
|
|
|
|
|
|
# Documented in POD |
4978
|
|
|
|
|
|
|
|
4979
|
|
|
|
|
|
|
sub __parse_angle { |
4980
|
40
|
|
|
40
|
|
140
|
my ( $self, @args ) = @_; |
4981
|
40
|
100
|
|
|
|
126
|
my $opt = HASH_REF eq ref $args[0] ? shift @args : {}; |
4982
|
40
|
|
|
|
|
85
|
my ( $angle ) = @args; |
4983
|
40
|
100
|
|
|
|
170
|
defined $angle or return; |
4984
|
|
|
|
|
|
|
|
4985
|
33
|
100
|
|
|
|
316
|
if ( $angle =~ m/ : /smx ) { |
|
|
100
|
|
|
|
|
|
4986
|
|
|
|
|
|
|
|
4987
|
2
|
|
|
|
|
19
|
my ($h, $m, $s) = split ':', $angle; |
4988
|
2
|
|
|
|
|
23
|
return _parse_angle_parts( |
4989
|
|
|
|
|
|
|
[ $h => 24 ], |
4990
|
|
|
|
|
|
|
[ $m => 60 ], |
4991
|
|
|
|
|
|
|
[ $s => 60 ], |
4992
|
|
|
|
|
|
|
); |
4993
|
|
|
|
|
|
|
|
4994
|
|
|
|
|
|
|
} elsif ( $angle =~ |
4995
|
|
|
|
|
|
|
m{ \A ( [-+] )? ( [0-9]* ) d |
4996
|
|
|
|
|
|
|
( [0-9]* (?: [.] [0-9]* )? ) (?: m |
4997
|
|
|
|
|
|
|
( [0-9]* (?: [.] [0-9]* )? ) s? )? \z |
4998
|
|
|
|
|
|
|
}smxi ) { |
4999
|
1
|
|
|
|
|
7
|
my ( $sgn, $deg, $min, $sec ) = ( $1, $2, $3, $4 ); |
5000
|
1
|
|
|
|
|
6
|
$angle = _parse_angle_parts( |
5001
|
|
|
|
|
|
|
[ $deg => 360 ], |
5002
|
|
|
|
|
|
|
[ $min => 60 ], |
5003
|
|
|
|
|
|
|
[ $sec => 60 ], |
5004
|
|
|
|
|
|
|
); |
5005
|
1
|
50
|
33
|
|
|
7
|
$sgn and '-' eq $sgn and return -$angle; |
5006
|
1
|
|
|
|
|
4
|
return $angle; |
5007
|
|
|
|
|
|
|
} |
5008
|
|
|
|
|
|
|
|
5009
|
|
|
|
|
|
|
$opt->{accept} |
5010
|
30
|
50
|
66
|
|
|
256
|
or looks_like_number( $angle ) |
5011
|
|
|
|
|
|
|
or $self->wail( "Invalid angle '$angle'" ); |
5012
|
|
|
|
|
|
|
|
5013
|
30
|
|
|
|
|
120
|
return $angle; |
5014
|
|
|
|
|
|
|
} |
5015
|
|
|
|
|
|
|
|
5016
|
|
|
|
|
|
|
# Documented in POD |
5017
|
|
|
|
|
|
|
{ |
5018
|
|
|
|
|
|
|
my %units = ( |
5019
|
|
|
|
|
|
|
au => AU, |
5020
|
|
|
|
|
|
|
ft => 0.0003048, |
5021
|
|
|
|
|
|
|
km => 1, |
5022
|
|
|
|
|
|
|
ly => LIGHTYEAR, |
5023
|
|
|
|
|
|
|
m => .001, |
5024
|
|
|
|
|
|
|
mi => 1.609344, |
5025
|
|
|
|
|
|
|
pc => PARSEC, |
5026
|
|
|
|
|
|
|
); |
5027
|
|
|
|
|
|
|
|
5028
|
|
|
|
|
|
|
sub __parse_distance { |
5029
|
3
|
|
|
3
|
|
21
|
my ($self, $string, $dfdist) = @_; |
5030
|
3
|
50
|
|
|
|
14
|
defined $dfdist or $dfdist = 'km'; |
5031
|
3
|
50
|
|
|
|
49
|
my $dfunits = $dfdist =~ s/ ( [[:alpha:]]+ ) \z //smx ? $1 : 'km'; |
5032
|
3
|
50
|
|
|
|
32
|
my $units = lc ( |
5033
|
|
|
|
|
|
|
$string =~ s/ \s* ( [[:alpha:]]+ ) \z //smx ? $1 : $dfunits ); |
5034
|
3
|
50
|
|
|
|
15
|
$units{$units} |
5035
|
|
|
|
|
|
|
or $self->wail( "Units of '$units' are unknown" ); |
5036
|
3
|
50
|
|
|
|
14
|
$string ne '' or $string = $dfdist; |
5037
|
3
|
50
|
|
|
|
16
|
looks_like_number ($string) |
5038
|
|
|
|
|
|
|
or $self->wail( "'$string' is not a number" ); |
5039
|
3
|
|
|
|
|
19
|
return $string * $units{$units}; |
5040
|
|
|
|
|
|
|
} |
5041
|
|
|
|
|
|
|
} |
5042
|
|
|
|
|
|
|
|
5043
|
|
|
|
|
|
|
# Documented in POD |
5044
|
|
|
|
|
|
|
|
5045
|
|
|
|
|
|
|
sub __parse_time { |
5046
|
55
|
|
|
55
|
|
2226
|
my ($self, $time, $default) = @_; |
5047
|
|
|
|
|
|
|
my $pt = $self->{time_parser} |
5048
|
55
|
50
|
|
|
|
198
|
or $self->wail( 'No time parser available' ); |
5049
|
55
|
50
|
|
|
|
291
|
$self->{time_parser}->can( 'station' ) |
5050
|
|
|
|
|
|
|
and $self->_set_time_parser_attribute( |
5051
|
|
|
|
|
|
|
station => $self->station() ); |
5052
|
55
|
50
|
|
|
|
229
|
if ( defined( my $time = $pt->parse( $time, $default ) ) ) { |
5053
|
55
|
|
|
|
|
149
|
return $time; |
5054
|
|
|
|
|
|
|
} |
5055
|
0
|
|
|
|
|
0
|
$self->wail( "Invalid time '$time'" ); |
5056
|
0
|
|
|
|
|
0
|
return; |
5057
|
|
|
|
|
|
|
} |
5058
|
|
|
|
|
|
|
|
5059
|
|
|
|
|
|
|
# Reset the last time set. This is called from __arguments() in |
5060
|
|
|
|
|
|
|
# ::Utils if the invocant is an Astro::App::Satpass2. |
5061
|
|
|
|
|
|
|
|
5062
|
|
|
|
|
|
|
sub __parse_time_reset { |
5063
|
332
|
|
|
332
|
|
707
|
my ( $self ) = @_; |
5064
|
|
|
|
|
|
|
defined ( my $pt = $self->{time_parser} ) |
5065
|
332
|
100
|
|
|
|
1030
|
or return; |
5066
|
311
|
|
|
|
|
1406
|
$pt->reset(); |
5067
|
311
|
|
|
|
|
613
|
return; |
5068
|
|
|
|
|
|
|
} |
5069
|
|
|
|
|
|
|
|
5070
|
|
|
|
|
|
|
# $string = _rad2hms ($angle) |
5071
|
|
|
|
|
|
|
|
5072
|
|
|
|
|
|
|
# Converts the given angle in radians to hours, minutes, and |
5073
|
|
|
|
|
|
|
# seconds (of right ascension, presumably) |
5074
|
|
|
|
|
|
|
|
5075
|
|
|
|
|
|
|
sub _rad2hms { |
5076
|
1
|
|
|
1
|
|
2
|
my $sec = shift; |
5077
|
1
|
|
|
|
|
8
|
$sec *= 12 / PI; |
5078
|
1
|
|
|
|
|
6
|
my $hr = floor( $sec ); |
5079
|
1
|
|
|
|
|
3
|
$sec = ( $sec - $hr ) * 60; |
5080
|
1
|
|
|
|
|
19
|
my $min = floor( $sec ); |
5081
|
1
|
|
|
|
|
11
|
$sec = ( $sec - $min ) * 60; |
5082
|
1
|
|
|
|
|
9
|
my $rslt = sprintf '%2d:%02d:%02d', $hr, $min, floor( $sec + .5 ); |
5083
|
1
|
|
|
|
|
8
|
return $rslt; |
5084
|
|
|
|
|
|
|
} |
5085
|
|
|
|
|
|
|
|
5086
|
|
|
|
|
|
|
# $line = $self->_read_continuation( $in, $error_message ); |
5087
|
|
|
|
|
|
|
# |
5088
|
|
|
|
|
|
|
# Acquire a line from $in, which must be a code reference taking |
5089
|
|
|
|
|
|
|
# the prompt as an argument. If $in is not a code reference, or if |
5090
|
|
|
|
|
|
|
# it returns undef, we wail() with the error message. Otherwise |
5091
|
|
|
|
|
|
|
# we return the line read. I expect this to be used only by |
5092
|
|
|
|
|
|
|
# __tokenize(). |
5093
|
|
|
|
|
|
|
|
5094
|
|
|
|
|
|
|
sub _read_continuation { |
5095
|
15
|
|
|
15
|
|
47
|
my ( $self, $in, $error ) = @_; |
5096
|
|
|
|
|
|
|
$in and defined( my $more = $in->( |
5097
|
|
|
|
|
|
|
my $prompt = $self->get( 'continuation_prompt' ) ) ) |
5098
|
15
|
100
|
66
|
|
|
102
|
or do { |
5099
|
1
|
50
|
|
|
|
4
|
$error or return; |
5100
|
1
|
50
|
|
|
|
3
|
ref $error eq CODE_REF |
5101
|
|
|
|
|
|
|
and return $error->(); |
5102
|
1
|
|
|
|
|
3
|
$self->wail( $error ); |
5103
|
|
|
|
|
|
|
}; |
5104
|
14
|
50
|
|
|
|
89
|
$self->{echo} and $self->whinge( $prompt, $more ); |
5105
|
14
|
100
|
|
|
|
87
|
$more =~ m/ \n \z /smx or $more .= "\n"; |
5106
|
14
|
|
|
|
|
43
|
return $more; |
5107
|
|
|
|
|
|
|
} |
5108
|
|
|
|
|
|
|
|
5109
|
|
|
|
|
|
|
# my ( $old_obj ) = $self->_replace_in_sky( $name, $new_obj ); |
5110
|
|
|
|
|
|
|
# This is restricted to objects constructed via {sky_class}. |
5111
|
|
|
|
|
|
|
# The return is an array containing the replaced body, or nothing if |
5112
|
|
|
|
|
|
|
# the body was not found. The $new_obj is optional; if not provided a |
5113
|
|
|
|
|
|
|
# new object is created. |
5114
|
|
|
|
|
|
|
sub _replace_in_sky { |
5115
|
0
|
|
|
0
|
|
0
|
my ( $self, $name, $new_obj ) = @_; |
5116
|
|
|
|
|
|
|
$new_obj |
5117
|
0
|
0
|
0
|
|
|
0
|
or $self->{sky_class}{ fold_case( $name ) } |
5118
|
|
|
|
|
|
|
or $self->weep( "Can not replace $name; no class defined" ); |
5119
|
0
|
0
|
|
|
|
0
|
defined( my $inx = $self->_find_in_sky( $name ) ) |
5120
|
|
|
|
|
|
|
or return; |
5121
|
0
|
|
0
|
|
|
0
|
return splice @{ $self->{sky} }, $inx, $inx + 1, |
|
0
|
|
|
|
|
0
|
|
5122
|
|
|
|
|
|
|
$new_obj || $self->_sky_object( $name ); |
5123
|
|
|
|
|
|
|
} |
5124
|
|
|
|
|
|
|
|
5125
|
|
|
|
|
|
|
# $self->_rewrite_level1_command( $buffer, $context ); |
5126
|
|
|
|
|
|
|
# |
5127
|
|
|
|
|
|
|
# This method rewrites a level1 command to its current form. The |
5128
|
|
|
|
|
|
|
# arguments are the buffer containing the command, and an |
5129
|
|
|
|
|
|
|
# initially-empty hash reference, which the method will use to |
5130
|
|
|
|
|
|
|
# preserve context across lines of command. NOTE that more than |
5131
|
|
|
|
|
|
|
# one rewritten command may be returned (e.g. 'almanac' into |
5132
|
|
|
|
|
|
|
# ( 'location', 'almanac' ). |
5133
|
|
|
|
|
|
|
|
5134
|
|
|
|
|
|
|
{ |
5135
|
|
|
|
|
|
|
|
5136
|
|
|
|
|
|
|
my %level1_map = ( |
5137
|
|
|
|
|
|
|
almanac => sub { |
5138
|
|
|
|
|
|
|
return ( 'location', $_[0] ); |
5139
|
|
|
|
|
|
|
}, |
5140
|
|
|
|
|
|
|
flare => sub { |
5141
|
|
|
|
|
|
|
local $_ = $_[0]; |
5142
|
|
|
|
|
|
|
s/ (?<= \s ) - ( am|pm|day ) \b /-no$1/sxmg; |
5143
|
|
|
|
|
|
|
return $_; |
5144
|
|
|
|
|
|
|
}, |
5145
|
|
|
|
|
|
|
pass => sub { |
5146
|
|
|
|
|
|
|
return ( 'location', $_[0] ); |
5147
|
|
|
|
|
|
|
}, |
5148
|
|
|
|
|
|
|
); |
5149
|
|
|
|
|
|
|
|
5150
|
|
|
|
|
|
|
my %level1_requote = ( |
5151
|
|
|
|
|
|
|
# In a macro definition: |
5152
|
|
|
|
|
|
|
macro => { |
5153
|
|
|
|
|
|
|
# In single-quoted strings, |
5154
|
|
|
|
|
|
|
q{'} => sub { |
5155
|
|
|
|
|
|
|
# escaped interpolations and double quotes may be |
5156
|
|
|
|
|
|
|
# unescaped, |
5157
|
|
|
|
|
|
|
s{ (?: \A | (?
|
5158
|
|
|
|
|
|
|
}{$1$2}sxmg; |
5159
|
|
|
|
|
|
|
# and the string remains single-quoted. |
5160
|
|
|
|
|
|
|
$_ = qq{'$_'}; |
5161
|
|
|
|
|
|
|
return; |
5162
|
|
|
|
|
|
|
}, |
5163
|
|
|
|
|
|
|
# In double-quoted strings, |
5164
|
|
|
|
|
|
|
q{"} => sub { |
5165
|
|
|
|
|
|
|
# escaped interpolations and double quotes may be |
5166
|
|
|
|
|
|
|
# unescaped, |
5167
|
|
|
|
|
|
|
s{ (?: \A | (?
|
5168
|
|
|
|
|
|
|
}{$1$2}sxmg; |
5169
|
|
|
|
|
|
|
# unescaped single quotes become double quotes, |
5170
|
|
|
|
|
|
|
s/ (?: \A | (?
|
5171
|
|
|
|
|
|
|
# and the string becomes single-quoted. |
5172
|
|
|
|
|
|
|
$_ = qq{'$_'}; |
5173
|
|
|
|
|
|
|
return; |
5174
|
|
|
|
|
|
|
}, |
5175
|
|
|
|
|
|
|
}, |
5176
|
|
|
|
|
|
|
# Anywhere else |
5177
|
|
|
|
|
|
|
'' => { |
5178
|
|
|
|
|
|
|
# In single-quoted strings, |
5179
|
|
|
|
|
|
|
q{'} => sub { |
5180
|
|
|
|
|
|
|
# unescaped double quotes must be escaped, |
5181
|
|
|
|
|
|
|
s/ (?: \A | (?
|
5182
|
|
|
|
|
|
|
# escaped single quotes may be unescaped, |
5183
|
|
|
|
|
|
|
s/ (?: \A | (?
|
5184
|
|
|
|
|
|
|
# and the string becomes double-quoted. |
5185
|
|
|
|
|
|
|
$_ = qq{"$_"}; |
5186
|
|
|
|
|
|
|
return; |
5187
|
|
|
|
|
|
|
}, |
5188
|
|
|
|
|
|
|
# In double-quoted strings, |
5189
|
|
|
|
|
|
|
q{"} => sub { |
5190
|
|
|
|
|
|
|
# no changes need to be made. |
5191
|
|
|
|
|
|
|
$_ = qq{"$_"}; |
5192
|
|
|
|
|
|
|
return; |
5193
|
|
|
|
|
|
|
}, |
5194
|
|
|
|
|
|
|
}, |
5195
|
|
|
|
|
|
|
); |
5196
|
|
|
|
|
|
|
|
5197
|
|
|
|
|
|
|
sub _rewrite_level1_command { |
5198
|
19
|
|
|
19
|
|
38
|
my ( undef, $buffer, $context ) = @_; # Invocant unused |
5199
|
|
|
|
|
|
|
|
5200
|
19
|
|
|
|
|
36
|
my $command = delete $context->{command}; |
5201
|
|
|
|
|
|
|
|
5202
|
19
|
100
|
|
|
|
45
|
defined $buffer |
5203
|
|
|
|
|
|
|
or return $buffer; |
5204
|
12
|
50
|
|
|
|
61
|
$buffer =~ m/ \A \s* \z /sxm |
5205
|
|
|
|
|
|
|
and return $buffer; |
5206
|
12
|
50
|
|
|
|
43
|
$buffer =~ s/ \A \s* [#] 2 [#] \s* //sxm |
5207
|
|
|
|
|
|
|
and return $buffer; |
5208
|
12
|
50
|
|
|
|
30
|
$buffer =~ m/ \A \s* [#] /sxm |
5209
|
|
|
|
|
|
|
and return $buffer; |
5210
|
|
|
|
|
|
|
|
5211
|
12
|
50
|
|
|
|
26
|
if ( ! defined $command ) { |
5212
|
12
|
100
|
|
|
|
41
|
$buffer =~ m/ \A \s* ( \w+ ) /sxm |
5213
|
|
|
|
|
|
|
or return $buffer; |
5214
|
11
|
|
|
|
|
32
|
$command = $1; |
5215
|
|
|
|
|
|
|
} |
5216
|
11
|
|
|
|
|
17
|
my $append = ''; |
5217
|
11
|
100
|
|
|
|
84
|
$buffer =~ s/ ( \s* \\? \n ) //sxm |
5218
|
|
|
|
|
|
|
and $append = $1; |
5219
|
|
|
|
|
|
|
$append =~ m/ \\ /sxm |
5220
|
11
|
50
|
|
|
|
31
|
and $context->{command} = $command; |
5221
|
|
|
|
|
|
|
|
5222
|
11
|
|
66
|
|
|
52
|
my $handler = $level1_requote{$command} || $level1_requote{''}; |
5223
|
11
|
|
|
|
|
49
|
my ( $this_quote, $start_pos ); |
5224
|
11
|
|
|
|
|
89
|
while ( $buffer =~ m/ (?: \A | (?
|
5225
|
|
|
|
|
|
|
) { |
5226
|
22
|
100
|
|
|
|
81
|
if ( ! defined $start_pos ) { |
|
|
100
|
|
|
|
|
|
5227
|
9
|
|
|
|
|
28
|
$start_pos = $+[0] - 1; |
5228
|
9
|
|
|
|
|
79
|
$this_quote = $1; |
5229
|
|
|
|
|
|
|
} elsif ( $1 eq $this_quote ) { |
5230
|
9
|
|
|
|
|
28
|
my $length = $+[0] - $start_pos; |
5231
|
9
|
|
|
|
|
28
|
local $_ = substr $buffer, $start_pos + 1, $length - 2; |
5232
|
9
|
|
|
|
|
32
|
$handler->{$this_quote}->(); |
5233
|
9
|
|
|
|
|
30
|
substr $buffer, $start_pos, $length, $_; |
5234
|
9
|
|
|
|
|
25
|
pos( $buffer ) = $start_pos + length $_; |
5235
|
9
|
|
|
|
|
38
|
$start_pos = undef; |
5236
|
|
|
|
|
|
|
} |
5237
|
|
|
|
|
|
|
} |
5238
|
|
|
|
|
|
|
|
5239
|
11
|
100
|
|
|
|
51
|
my $code = $level1_map{$command} |
5240
|
|
|
|
|
|
|
or return $buffer . $append; |
5241
|
|
|
|
|
|
|
|
5242
|
3
|
|
|
|
|
13
|
my @rslt = $code->( $buffer ); |
5243
|
3
|
|
|
|
|
8
|
$rslt[-1] .= $append; |
5244
|
3
|
|
|
|
|
12
|
return @rslt; |
5245
|
|
|
|
|
|
|
|
5246
|
|
|
|
|
|
|
} |
5247
|
|
|
|
|
|
|
} |
5248
|
|
|
|
|
|
|
|
5249
|
|
|
|
|
|
|
# $self->_rewrite_level1_macros(); |
5250
|
|
|
|
|
|
|
# |
5251
|
|
|
|
|
|
|
# This method rewrites all macros defined by a satpass |
5252
|
|
|
|
|
|
|
# initialization file (as opposed to a satpass2 initialization |
5253
|
|
|
|
|
|
|
# file) to be satpass2-compatible. It also clears the level1 flag |
5254
|
|
|
|
|
|
|
# so that the satpass-compatible functionality is not invoked. |
5255
|
|
|
|
|
|
|
# |
5256
|
|
|
|
|
|
|
# Specifically it: |
5257
|
|
|
|
|
|
|
# * Inserts a 'location' command before 'almanac' and 'pass'; |
5258
|
|
|
|
|
|
|
# * Changes the senses of the -am, -day, and -pm options in |
5259
|
|
|
|
|
|
|
# 'flare'; |
5260
|
|
|
|
|
|
|
# * Removes delegated attributes from 'localize', replacing them |
5261
|
|
|
|
|
|
|
# with a localization of the helper object. |
5262
|
|
|
|
|
|
|
# |
5263
|
|
|
|
|
|
|
# This method goes away when the satpass functionality does. |
5264
|
|
|
|
|
|
|
|
5265
|
|
|
|
|
|
|
{ |
5266
|
|
|
|
|
|
|
my %helper_map = ( |
5267
|
|
|
|
|
|
|
date_format => { |
5268
|
|
|
|
|
|
|
helper => 'formatter', # Helper obj attr. Req'd. |
5269
|
|
|
|
|
|
|
}, |
5270
|
|
|
|
|
|
|
desired_equinox_dynamical => { |
5271
|
|
|
|
|
|
|
helper => 'formatter', |
5272
|
|
|
|
|
|
|
}, |
5273
|
|
|
|
|
|
|
gmt => { |
5274
|
|
|
|
|
|
|
helper => 'formatter', |
5275
|
|
|
|
|
|
|
}, |
5276
|
|
|
|
|
|
|
local_coord => { |
5277
|
|
|
|
|
|
|
helper => 'formatter', |
5278
|
|
|
|
|
|
|
}, |
5279
|
|
|
|
|
|
|
time_format => { |
5280
|
|
|
|
|
|
|
helper => 'formatter', |
5281
|
|
|
|
|
|
|
}, |
5282
|
|
|
|
|
|
|
); |
5283
|
|
|
|
|
|
|
|
5284
|
|
|
|
|
|
|
my %filter = ( |
5285
|
|
|
|
|
|
|
almanac => sub { |
5286
|
|
|
|
|
|
|
my ( undef, $line ) = @_; # $verb unused |
5287
|
|
|
|
|
|
|
return ( 'location', $line ); |
5288
|
|
|
|
|
|
|
}, |
5289
|
|
|
|
|
|
|
flare => sub { |
5290
|
|
|
|
|
|
|
my ( undef, $line ) = @_; # $verb unused |
5291
|
|
|
|
|
|
|
$line =~ s/ (?<= \s ) - (am|day|pm) \b /-no$1/smx; |
5292
|
|
|
|
|
|
|
return $line; |
5293
|
|
|
|
|
|
|
}, |
5294
|
|
|
|
|
|
|
localize => sub { |
5295
|
|
|
|
|
|
|
my ( undef, $line ) = @_; # $verb unused |
5296
|
|
|
|
|
|
|
my @things = split qr{ \s+ }smx, $line; |
5297
|
|
|
|
|
|
|
my @output; |
5298
|
|
|
|
|
|
|
my %duplicate; |
5299
|
|
|
|
|
|
|
foreach my $token ( @things ) { |
5300
|
|
|
|
|
|
|
$helper_map{$token} |
5301
|
|
|
|
|
|
|
and $token = $helper_map{$token}{helper}; |
5302
|
|
|
|
|
|
|
$duplicate{$token}++ or push @output, $token; |
5303
|
|
|
|
|
|
|
} |
5304
|
|
|
|
|
|
|
return join ' ', @output; |
5305
|
|
|
|
|
|
|
}, |
5306
|
|
|
|
|
|
|
pass => sub { |
5307
|
|
|
|
|
|
|
my ( undef, $line ) = @_; # $verb unused |
5308
|
|
|
|
|
|
|
return ( 'location', $line ); |
5309
|
|
|
|
|
|
|
}, |
5310
|
|
|
|
|
|
|
set => sub { |
5311
|
|
|
|
|
|
|
my ( undef, $line ) = @_; # $verb unused |
5312
|
|
|
|
|
|
|
my @output = [ 'fubar' ]; # Prime the pump. |
5313
|
|
|
|
|
|
|
my @input = Text::ParseWords::quotewords( qr{ \s+ }smx, 1, |
5314
|
|
|
|
|
|
|
$line ); |
5315
|
|
|
|
|
|
|
shift @input; |
5316
|
|
|
|
|
|
|
while ( @input ) { |
5317
|
|
|
|
|
|
|
my ( $attr, $val ) = splice @input, 0, 2; |
5318
|
|
|
|
|
|
|
if ( my $helper = $helper_map{$attr} ) { |
5319
|
|
|
|
|
|
|
push @output, [ $helper->{helper}, |
5320
|
|
|
|
|
|
|
# not quoter( $val ) here, because presumably it |
5321
|
|
|
|
|
|
|
# is already quoted if it needs to be. |
5322
|
|
|
|
|
|
|
$helper->{attribute} || $attr, $val ]; |
5323
|
|
|
|
|
|
|
} else { |
5324
|
|
|
|
|
|
|
'set' eq $output[-1][0] |
5325
|
|
|
|
|
|
|
or push @output, [ 'set' ]; |
5326
|
|
|
|
|
|
|
# not quoter( $val ) here, because presumably it is |
5327
|
|
|
|
|
|
|
# already quoted if it needs to be. |
5328
|
|
|
|
|
|
|
push @{ $output[-1] }, $attr, $val; |
5329
|
|
|
|
|
|
|
} |
5330
|
|
|
|
|
|
|
} |
5331
|
|
|
|
|
|
|
shift @output; # Get rid of the pump priming. |
5332
|
|
|
|
|
|
|
return ( map { join ' ', @{ $_ } } @output ); |
5333
|
|
|
|
|
|
|
}, |
5334
|
|
|
|
|
|
|
st => sub { |
5335
|
|
|
|
|
|
|
my ( undef, $line ) = @_; # $verb unused |
5336
|
|
|
|
|
|
|
m/ \A \s* st \s+ localize \b /smx |
5337
|
|
|
|
|
|
|
and return $line; |
5338
|
|
|
|
|
|
|
$line =~ s/ \b st \b /spacetrack/smx; |
5339
|
|
|
|
|
|
|
return $line; |
5340
|
|
|
|
|
|
|
}, |
5341
|
|
|
|
|
|
|
show => sub { |
5342
|
|
|
|
|
|
|
my ( undef, $line ) = @_; # $verb unused |
5343
|
|
|
|
|
|
|
my @output = [ 'fubar' ]; |
5344
|
|
|
|
|
|
|
my @input = split qr{ \s+ }smx, $line; |
5345
|
|
|
|
|
|
|
shift @input; |
5346
|
|
|
|
|
|
|
foreach my $attr ( @input ) { |
5347
|
|
|
|
|
|
|
if ( my $helper = $helper_map{$attr} ) { |
5348
|
|
|
|
|
|
|
push @output, [ $helper->{helper}, |
5349
|
|
|
|
|
|
|
$helper->{attribute} || $attr ]; |
5350
|
|
|
|
|
|
|
} else { |
5351
|
|
|
|
|
|
|
'show' eq $output[-1][0] |
5352
|
|
|
|
|
|
|
or push @output, [ 'show' ]; |
5353
|
|
|
|
|
|
|
push @{ $output[-1] }, $attr; |
5354
|
|
|
|
|
|
|
} |
5355
|
|
|
|
|
|
|
} |
5356
|
|
|
|
|
|
|
shift @output; |
5357
|
|
|
|
|
|
|
return ( map { join ' ', @{ $_ } } @output ); |
5358
|
|
|
|
|
|
|
}, |
5359
|
|
|
|
|
|
|
); |
5360
|
|
|
|
|
|
|
|
5361
|
|
|
|
|
|
|
# Called by macro object's __level1_rewrite(). |
5362
|
|
|
|
|
|
|
sub __rewrite_level1_macro_def { |
5363
|
8
|
|
|
8
|
|
16
|
my ( $self, $name, $args ) = @_; |
5364
|
|
|
|
|
|
|
|
5365
|
8
|
|
|
|
|
13
|
my ( $rewrote, @rslt ); |
5366
|
8
|
|
|
|
|
10
|
foreach ( @{ $args } ) { |
|
8
|
|
|
|
|
29
|
|
5367
|
8
|
100
|
100
|
|
|
75
|
if ( m/ ( \S+ ) /smx |
|
|
|
66
|
|
|
|
|
|
|
|
66
|
|
|
|
|
5368
|
|
|
|
|
|
|
and ( not $self->{macro}{$1} |
5369
|
|
|
|
|
|
|
or $1 eq $name ) |
5370
|
|
|
|
|
|
|
and my $code = $filter{$1} ) { |
5371
|
7
|
|
|
|
|
35
|
push @rslt, $code->( $1, $_ ); |
5372
|
7
|
|
|
|
|
16
|
$rewrote++; |
5373
|
|
|
|
|
|
|
} else { |
5374
|
1
|
|
|
|
|
4
|
push @rslt, $_; |
5375
|
|
|
|
|
|
|
} |
5376
|
|
|
|
|
|
|
} |
5377
|
|
|
|
|
|
|
|
5378
|
8
|
100
|
|
|
|
30
|
return $rewrote ? \@rslt : $args; |
5379
|
|
|
|
|
|
|
} |
5380
|
|
|
|
|
|
|
|
5381
|
|
|
|
|
|
|
sub _rewrite_level1_macros { |
5382
|
4
|
|
|
4
|
|
9
|
my ( $self ) = @_; |
5383
|
|
|
|
|
|
|
|
5384
|
4
|
|
|
|
|
4
|
foreach my $macro ( values %{ $self->{macro} } ) { |
|
4
|
|
|
|
|
11
|
|
5385
|
8
|
|
|
|
|
22
|
$macro->__level1_rewrite(); |
5386
|
|
|
|
|
|
|
} |
5387
|
|
|
|
|
|
|
|
5388
|
4
|
|
|
|
|
7
|
return; |
5389
|
|
|
|
|
|
|
} |
5390
|
|
|
|
|
|
|
} |
5391
|
|
|
|
|
|
|
|
5392
|
|
|
|
|
|
|
# @coordinates = $self->_simbad4 ($query) |
5393
|
|
|
|
|
|
|
|
5394
|
|
|
|
|
|
|
# Look up the given star in the SIMBAD catalog. This assumes |
5395
|
|
|
|
|
|
|
# SIMBAD 4. |
5396
|
|
|
|
|
|
|
|
5397
|
|
|
|
|
|
|
# We die on any error. |
5398
|
|
|
|
|
|
|
|
5399
|
|
|
|
|
|
|
sub _simbad4 { |
5400
|
0
|
|
|
0
|
|
0
|
my $self = shift; |
5401
|
0
|
|
|
|
|
0
|
$self->_load_module ('Astro::SIMBAD::Client'); |
5402
|
0
|
|
|
|
|
0
|
my $query = shift; |
5403
|
|
|
|
|
|
|
my $simbad = Astro::SIMBAD::Client->new ( |
5404
|
|
|
|
|
|
|
format => {txt => 'FORMAT_TXT_SIMPLE_BASIC'}, |
5405
|
|
|
|
|
|
|
parser => { |
5406
|
|
|
|
|
|
|
script => 'Parse_TXT_Simple', |
5407
|
|
|
|
|
|
|
txt => 'Parse_TXT_Simple', |
5408
|
|
|
|
|
|
|
}, |
5409
|
|
|
|
|
|
|
server => $self->{simbad_url}, |
5410
|
0
|
|
|
|
|
0
|
type => 'txt', |
5411
|
|
|
|
|
|
|
); |
5412
|
|
|
|
|
|
|
# I prefer script() to query() these days because the former does |
5413
|
|
|
|
|
|
|
# not require SOAP::Lite, which seems to be getting flakier as time |
5414
|
|
|
|
|
|
|
# goes on. |
5415
|
|
|
|
|
|
|
# TODO get rid of $fmt =~ s/// once I massage |
5416
|
|
|
|
|
|
|
# FORMAT_TXT_SIMPLE_BASIC in Astro::SIMBAD::Client |
5417
|
|
|
|
|
|
|
# my @rslt = $simbad->query (id => $query) |
5418
|
0
|
|
|
|
|
0
|
my $fmt = Astro::SIMBAD::Client->FORMAT_TXT_SIMPLE_BASIC(); |
5419
|
0
|
|
|
|
|
0
|
$fmt =~ s/ \n //smxg; |
5420
|
0
|
0
|
|
|
|
0
|
my @rslt = $simbad->script( <<"EOD" ) |
5421
|
|
|
|
|
|
|
format obj "$fmt" |
5422
|
|
|
|
|
|
|
query id $query |
5423
|
|
|
|
|
|
|
EOD |
5424
|
|
|
|
|
|
|
or $self->wail("No entry found for $query"); |
5425
|
0
|
0
|
|
|
|
0
|
@rslt > 1 |
5426
|
|
|
|
|
|
|
and $self->wail("More than one entry found for $query"); |
5427
|
0
|
0
|
0
|
|
|
0
|
@rslt = map {$rslt[0]{$_} eq '~' ? 0 : $rslt[0]{$_} || 0} qw{ |
|
0
|
|
|
|
|
0
|
|
5428
|
|
|
|
|
|
|
ra dec plx pmra pmdec radial}; |
5429
|
0
|
0
|
0
|
|
|
0
|
($rslt[0] && $rslt[1]) |
5430
|
|
|
|
|
|
|
or $self->wail("No position returned by $query"); |
5431
|
0
|
0
|
|
|
|
0
|
$rslt[2] = $rslt[2] ? 1000 / $rslt[2] : 10000; |
5432
|
0
|
0
|
|
|
|
0
|
$rslt[3] and $rslt[3] /= 1000; |
5433
|
0
|
0
|
|
|
|
0
|
$rslt[4] and $rslt[4] /= 1000; |
5434
|
0
|
0
|
|
|
|
0
|
return wantarray ? @rslt : join ' ', @rslt; |
5435
|
|
|
|
|
|
|
} |
5436
|
|
|
|
|
|
|
|
5437
|
|
|
|
|
|
|
sub _templates_to_options { |
5438
|
24
|
|
|
24
|
|
141
|
my ( $self, $name, $opt ) = @_; |
5439
|
24
|
|
|
|
|
90
|
$opt->{_template} = $name; |
5440
|
|
|
|
|
|
|
my $code = sub { |
5441
|
5
|
|
|
5
|
|
3006
|
my ( $opt_name, $opt_value ) = @_; |
5442
|
5
|
50
|
|
|
|
75
|
$opt->{_template} = $opt_value ? "${name}_$opt_name" : $name; |
5443
|
5
|
|
|
|
|
33
|
return; |
5444
|
24
|
|
|
|
|
170
|
}; |
5445
|
24
|
|
|
|
|
215
|
my $re = qr< \A \Q$name\E _ ( \w+ ) \z >smx; |
5446
|
24
|
|
|
|
|
75
|
my @rslt; |
5447
|
24
|
|
|
|
|
114
|
my $fmtr = $self->get( 'formatter' ); |
5448
|
24
|
50
|
|
|
|
262
|
if ( $fmtr->can( '__list_templates' ) ) { |
5449
|
24
|
|
|
|
|
124
|
foreach ( $fmtr->__list_templates() ) { |
5450
|
672
|
100
|
|
|
|
1987
|
$_ =~ $re |
5451
|
|
|
|
|
|
|
or next; |
5452
|
44
|
|
|
|
|
195
|
push @rslt, "$1!", $code; |
5453
|
|
|
|
|
|
|
} |
5454
|
|
|
|
|
|
|
} |
5455
|
24
|
|
|
|
|
351
|
return @rslt; |
5456
|
|
|
|
|
|
|
} |
5457
|
|
|
|
|
|
|
|
5458
|
|
|
|
|
|
|
# ($tokens, $redirect) = $self->__tokenize( |
5459
|
|
|
|
|
|
|
# {option => $value}, $buffer, [$arg0 ...]); |
5460
|
|
|
|
|
|
|
# |
5461
|
|
|
|
|
|
|
# This method tokenizes the buffer. The options hash may be |
5462
|
|
|
|
|
|
|
# omitted, in which case the $buffer to be tokenized is the first |
5463
|
|
|
|
|
|
|
# argument. After the buffer is an optional reference to an array |
5464
|
|
|
|
|
|
|
# of arguments to be substituted in. |
5465
|
|
|
|
|
|
|
# |
5466
|
|
|
|
|
|
|
# This method attempts to parse and tokenize the buffer in a way |
5467
|
|
|
|
|
|
|
# similar to the bash shell. That is, parameters are interpolated |
5468
|
|
|
|
|
|
|
# inside double quotes but not single quotes, tilde expansion |
5469
|
|
|
|
|
|
|
# takes place unless quoted, and spaces delimit tokens only when |
5470
|
|
|
|
|
|
|
# occurring outside quotes. |
5471
|
|
|
|
|
|
|
# |
5472
|
|
|
|
|
|
|
# The back slash character ('\') is an escape character. Inside |
5473
|
|
|
|
|
|
|
# single quotes only the back slash itself and a single quote may |
5474
|
|
|
|
|
|
|
# be escaped. Otherwise, anything can be escaped. |
5475
|
|
|
|
|
|
|
# |
5476
|
|
|
|
|
|
|
# The returns are a reference to an array of tokens found, and a |
5477
|
|
|
|
|
|
|
# reference to a hash of redirections found. This hash will have |
5478
|
|
|
|
|
|
|
# zero or more of the keys '>' (standard output redirection) and |
5479
|
|
|
|
|
|
|
# '<' (standard input redirection. The value of each key will be a |
5480
|
|
|
|
|
|
|
# reference to a hash containing keys 'mode' ('>' or '>>' for |
5481
|
|
|
|
|
|
|
# output, '<' or '<<' for input) and 'name' (normally the file |
5482
|
|
|
|
|
|
|
# name). |
5483
|
|
|
|
|
|
|
# |
5484
|
|
|
|
|
|
|
# The recognized options are: |
5485
|
|
|
|
|
|
|
# |
5486
|
|
|
|
|
|
|
# single => 1 |
5487
|
|
|
|
|
|
|
# causes the buffer to be interpreted as a single token. |
5488
|
|
|
|
|
|
|
# |
5489
|
|
|
|
|
|
|
# noredirect => 1 |
5490
|
|
|
|
|
|
|
# causes redirects to be illegal. |
5491
|
|
|
|
|
|
|
# |
5492
|
|
|
|
|
|
|
# If noredirect is specified, only the $tokens reference is |
5493
|
|
|
|
|
|
|
# returned. If noredirect and single are both specified, the |
5494
|
|
|
|
|
|
|
# parsed and interpolated token is returned. |
5495
|
|
|
|
|
|
|
# |
5496
|
|
|
|
|
|
|
# If interpolation is being done, an unescaped dollar sign |
5497
|
|
|
|
|
|
|
# introduces the interpolation. This works pretty much the same |
5498
|
|
|
|
|
|
|
# way as under bash: if the first character after the dollar sign |
5499
|
|
|
|
|
|
|
# is a left curly bracket, everything to the corresponding right |
5500
|
|
|
|
|
|
|
# curly bracked specifies the interpolation; if not, the rule is |
5501
|
|
|
|
|
|
|
# that word characters specify the interpolation. |
5502
|
|
|
|
|
|
|
# |
5503
|
|
|
|
|
|
|
# A number (i.e. $1) specifies interpolation of an argument. |
5504
|
|
|
|
|
|
|
# Arguments are numbered starting at 1. |
5505
|
|
|
|
|
|
|
# |
5506
|
|
|
|
|
|
|
# Otherwise, if the interpolation names an attribute, the value of |
5507
|
|
|
|
|
|
|
# that attribute is interpolated in, otherwise the named |
5508
|
|
|
|
|
|
|
# environment variable is interpolated in. |
5509
|
|
|
|
|
|
|
# |
5510
|
|
|
|
|
|
|
# Most of the fancier forms of interpolation are suported. In the |
5511
|
|
|
|
|
|
|
# following, word is expanded by recursively calling __tokenize |
5512
|
|
|
|
|
|
|
# with options {single => 1, noredirect => 1}. But unlike bash, we |
5513
|
|
|
|
|
|
|
# make no distinction between unset or null. The ':' can be |
5514
|
|
|
|
|
|
|
# omitted before the '-', '=', '?' or '+', but it does not change |
5515
|
|
|
|
|
|
|
# the functionality. |
5516
|
|
|
|
|
|
|
# |
5517
|
|
|
|
|
|
|
# ${parameter:-word} causes the given word to be substituted if |
5518
|
|
|
|
|
|
|
# the parameter is undefined. |
5519
|
|
|
|
|
|
|
# |
5520
|
|
|
|
|
|
|
# ${parameter:=word} is the same as above, but also causes the |
5521
|
|
|
|
|
|
|
# word to be assigned to the parameter if it is unassigned. Unlike |
5522
|
|
|
|
|
|
|
# bash, this assignment takes place on positional parameters. If |
5523
|
|
|
|
|
|
|
# done on an attribute or environment variable, it causes that |
5524
|
|
|
|
|
|
|
# attribute or environment variable to be set to the given value. |
5525
|
|
|
|
|
|
|
# |
5526
|
|
|
|
|
|
|
# ${parameter:?word} causes the parse to fail with the error |
5527
|
|
|
|
|
|
|
# 'word' if the parameter is undefined. |
5528
|
|
|
|
|
|
|
# |
5529
|
|
|
|
|
|
|
# ${parameter:+word} causes the value of the given word to be used |
5530
|
|
|
|
|
|
|
# if the parameter is defined, otherwise '' is used. |
5531
|
|
|
|
|
|
|
# |
5532
|
|
|
|
|
|
|
# ${parameter:offset} and ${parameter:offset:length} take |
5533
|
|
|
|
|
|
|
# substrings of the parameter value. The offset and length must be |
5534
|
|
|
|
|
|
|
# numeric. |
5535
|
|
|
|
|
|
|
|
5536
|
|
|
|
|
|
|
{ |
5537
|
|
|
|
|
|
|
|
5538
|
|
|
|
|
|
|
# Special variables. |
5539
|
|
|
|
|
|
|
# Calling sequence: $special{$name}->(\@args, $relquote) |
5540
|
|
|
|
|
|
|
my %special = ( |
5541
|
|
|
|
|
|
|
'0' => sub { return $0 }, |
5542
|
|
|
|
|
|
|
'#' => sub { return scalar @{ $_[0] } }, |
5543
|
|
|
|
|
|
|
## '*' => sub { return join ' ', @{ $_[0] } }, |
5544
|
|
|
|
|
|
|
## '@' => sub { return $_[1] ? join( ' ', @{ $_[0] } ) : $_[0] }, |
5545
|
|
|
|
|
|
|
'*' => sub { return $_[1] ? join( ' ', @{ $_[0] } ) : $_[0] }, |
5546
|
|
|
|
|
|
|
'@' => sub { return $_[0] }, |
5547
|
|
|
|
|
|
|
'$' => sub { return $$ }, |
5548
|
|
|
|
|
|
|
'_' => sub { return $^X }, |
5549
|
|
|
|
|
|
|
); |
5550
|
|
|
|
|
|
|
|
5551
|
|
|
|
|
|
|
my %case_ctl = ( |
5552
|
|
|
|
|
|
|
E => sub { delete $_[0]->{_case_mod} }, |
5553
|
|
|
|
|
|
|
F => sub { $_[0]->{_case_mod}{case} = sub { fold_case( $_[1] ) } }, |
5554
|
|
|
|
|
|
|
L => sub { $_[0]->{_case_mod}{case} = sub { lc $_[1] } }, |
5555
|
|
|
|
|
|
|
U => sub { $_[0]->{_case_mod}{case} = sub { uc $_[1] } }, |
5556
|
|
|
|
|
|
|
l => sub { $_[0]->{_case_mod}{single} = sub { lcfirst $_[1] } }, |
5557
|
|
|
|
|
|
|
u => sub { $_[0]->{_case_mod}{single} = sub { ucfirst $_[1] } }, |
5558
|
|
|
|
|
|
|
); |
5559
|
|
|
|
|
|
|
|
5560
|
|
|
|
|
|
|
# Leading punctuation that is equivalent to a method. |
5561
|
|
|
|
|
|
|
my %command_equivalent = ( |
5562
|
|
|
|
|
|
|
'.' => 'source', |
5563
|
|
|
|
|
|
|
'!' => 'system', |
5564
|
|
|
|
|
|
|
); |
5565
|
|
|
|
|
|
|
my $command_equiv_re = do { |
5566
|
|
|
|
|
|
|
my $keys = join '', sort keys %command_equivalent; |
5567
|
|
|
|
|
|
|
qr{ [$keys] }smx; |
5568
|
|
|
|
|
|
|
}; |
5569
|
|
|
|
|
|
|
|
5570
|
|
|
|
|
|
|
my %escape = ( |
5571
|
|
|
|
|
|
|
t => "\t", |
5572
|
|
|
|
|
|
|
n => "\n", |
5573
|
|
|
|
|
|
|
r => "\r", |
5574
|
|
|
|
|
|
|
f => "\f", |
5575
|
|
|
|
|
|
|
b => "\b", |
5576
|
|
|
|
|
|
|
a => "\a", |
5577
|
|
|
|
|
|
|
e => "\e", |
5578
|
|
|
|
|
|
|
); |
5579
|
|
|
|
|
|
|
|
5580
|
|
|
|
|
|
|
sub __tokenize { |
5581
|
381
|
|
|
381
|
|
69843
|
my ($self, @parms) = @_; |
5582
|
381
|
|
|
|
|
1071
|
local $self->{_case_mod} = undef; |
5583
|
381
|
100
|
|
|
|
1158
|
my $opt = HASH_REF eq ref $parms[0] ? shift @parms : {}; |
5584
|
381
|
|
|
|
|
716
|
my $in = $opt->{in}; |
5585
|
381
|
|
|
|
|
788
|
my $buffer = shift @parms; |
5586
|
381
|
100
|
|
|
|
1390
|
$buffer =~ m/ \n \z /smx or $buffer .= "\n"; |
5587
|
381
|
|
100
|
|
|
858
|
my $args = shift @parms || []; |
5588
|
381
|
|
|
|
|
762
|
my @rslt = ( {} ); |
5589
|
381
|
|
|
|
|
661
|
my $absquote; # True if inside '' |
5590
|
|
|
|
|
|
|
my $relquote; # True if inside "" (and not in '') |
5591
|
381
|
|
|
|
|
605
|
my $len = length $buffer; |
5592
|
381
|
|
|
|
|
548
|
my $inx = 0; |
5593
|
|
|
|
|
|
|
|
5594
|
|
|
|
|
|
|
# Because I'm not smart enough to do all this with a regular |
5595
|
|
|
|
|
|
|
# expression, I take the brute force approach and iterate |
5596
|
|
|
|
|
|
|
# through the buffer to be tokenized. It's a 'while' rather than |
5597
|
|
|
|
|
|
|
# a 'for' or 'foreach' because that way I get to muck around |
5598
|
|
|
|
|
|
|
# with the current position inside the loop. |
5599
|
|
|
|
|
|
|
|
5600
|
381
|
|
|
|
|
782
|
while ($inx < $len) { |
5601
|
6312
|
|
|
|
|
10599
|
my $char = substr $buffer, $inx++, 1; |
5602
|
|
|
|
|
|
|
|
5603
|
|
|
|
|
|
|
# If we're inside single quotes, the only escapable |
5604
|
|
|
|
|
|
|
# characters are single quote and back slash, and all |
5605
|
|
|
|
|
|
|
# characters until the next unescaped single quote go into |
5606
|
|
|
|
|
|
|
# the current token |
5607
|
|
|
|
|
|
|
|
5608
|
6312
|
100
|
66
|
|
|
38565
|
if ( $absquote ) { |
|
|
100
|
100
|
|
|
|
|
|
|
100
|
100
|
|
|
|
|
|
|
100
|
66
|
|
|
|
|
|
|
100
|
66
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
5609
|
621
|
50
|
|
|
|
1187
|
if ( $char eq '\\' ) { |
|
|
100
|
|
|
|
|
|
5610
|
0
|
0
|
|
|
|
0
|
if ( (my $next = substr $buffer, $inx, 1) =~ |
5611
|
|
|
|
|
|
|
m/ ['\\] /smx ) { |
5612
|
0
|
|
|
|
|
0
|
$inx++; |
5613
|
0
|
|
|
|
|
0
|
$rslt[-1]{token} .= $next; |
5614
|
|
|
|
|
|
|
} else { |
5615
|
0
|
|
|
|
|
0
|
$rslt[-1]{token} .= $char; |
5616
|
|
|
|
|
|
|
} |
5617
|
|
|
|
|
|
|
} elsif ( $char eq q{'} ) { |
5618
|
34
|
|
|
|
|
85
|
$absquote = undef; |
5619
|
|
|
|
|
|
|
} else { |
5620
|
587
|
|
|
|
|
819
|
$rslt[-1]{token} .= $char; |
5621
|
587
|
100
|
|
|
|
1047
|
if ( $inx >= $len ) { |
5622
|
2
|
|
|
|
|
11
|
$buffer .= $self->_read_continuation( $in, |
5623
|
|
|
|
|
|
|
'Unclosed single quote' ); |
5624
|
1
|
|
|
|
|
2
|
$len = length $buffer; |
5625
|
|
|
|
|
|
|
} |
5626
|
|
|
|
|
|
|
} |
5627
|
|
|
|
|
|
|
|
5628
|
|
|
|
|
|
|
# If we have a backslash, it escapes the next character, |
5629
|
|
|
|
|
|
|
# which goes on the current token no matter what it is. |
5630
|
|
|
|
|
|
|
|
5631
|
|
|
|
|
|
|
} elsif ( $char eq '\\' ) { |
5632
|
10
|
|
|
|
|
32
|
my $next = substr $buffer, $inx++, 1; |
5633
|
10
|
100
|
|
|
|
43
|
if ( $inx >= $len ) { # At end of line |
|
|
100
|
|
|
|
|
|
5634
|
2
|
50
|
|
|
|
25
|
if ( $relquote ) { # Inside "" |
5635
|
0
|
|
|
|
|
0
|
$buffer .= $self->_read_continuation( $in, |
5636
|
|
|
|
|
|
|
'Unclosed double quote' ); |
5637
|
|
|
|
|
|
|
} else { # Between tokens |
5638
|
2
|
|
|
|
|
29
|
$buffer .= $self->_read_continuation( $in, |
5639
|
|
|
|
|
|
|
'Dangling continuation' ); |
5640
|
2
|
50
|
|
|
|
26
|
$opt->{single} or push @rslt, {}; # New token |
5641
|
|
|
|
|
|
|
} |
5642
|
2
|
|
|
|
|
15
|
$len = length $buffer; |
5643
|
|
|
|
|
|
|
} elsif ( $relquote ) { |
5644
|
7
|
100
|
|
|
|
25
|
if ( my $code = $case_ctl{$next} ) { |
5645
|
6
|
|
|
|
|
37
|
$code->( $self ); |
5646
|
|
|
|
|
|
|
} else { |
5647
|
1
|
|
33
|
|
|
4
|
$rslt[-1]{token} .= $escape{$next} || $next; |
5648
|
|
|
|
|
|
|
} |
5649
|
|
|
|
|
|
|
} else { |
5650
|
1
|
|
|
|
|
3
|
$rslt[-1]{token} .= $next; |
5651
|
|
|
|
|
|
|
} |
5652
|
|
|
|
|
|
|
|
5653
|
|
|
|
|
|
|
# If we have a single quote and we're not inside double |
5654
|
|
|
|
|
|
|
# quotes, we go into absolute quote mode. We also append an |
5655
|
|
|
|
|
|
|
# empty string to the current token to force its value to be |
5656
|
|
|
|
|
|
|
# defined; otherwise empty quotes do not generate tokens. |
5657
|
|
|
|
|
|
|
|
5658
|
|
|
|
|
|
|
} elsif ($char eq q{'} && !$relquote) { |
5659
|
35
|
|
|
|
|
90
|
$rslt[-1]{token} .= ''; # Empty string, to force defined. |
5660
|
35
|
|
|
|
|
98
|
$absquote++; |
5661
|
|
|
|
|
|
|
|
5662
|
|
|
|
|
|
|
# If we have a double quote, we toggle relative quote mode. |
5663
|
|
|
|
|
|
|
# We also append an empty string to the current tokens for |
5664
|
|
|
|
|
|
|
# the reasons discussed above. |
5665
|
|
|
|
|
|
|
|
5666
|
|
|
|
|
|
|
} elsif ($char eq '"') { |
5667
|
44
|
|
|
|
|
93
|
$rslt[-1]{token} .= ''; # Empty string, to force defined. |
5668
|
|
|
|
|
|
|
( $relquote = !$relquote ) |
5669
|
44
|
100
|
|
|
|
128
|
or delete $self->{_case_mod}; |
5670
|
|
|
|
|
|
|
|
5671
|
|
|
|
|
|
|
# If we have a whitespace character and we're not inside |
5672
|
|
|
|
|
|
|
# quotes and not in single-token mode, we start a new token. |
5673
|
|
|
|
|
|
|
# It is possible that we generate redundant tokens this way, |
5674
|
|
|
|
|
|
|
# but the unused ones are eliminated later. |
5675
|
|
|
|
|
|
|
|
5676
|
|
|
|
|
|
|
} elsif ($char =~ m/ \s /smx && !$relquote && !$opt->{single}) { |
5677
|
937
|
|
|
|
|
1788
|
push @rslt, {}; |
5678
|
|
|
|
|
|
|
|
5679
|
|
|
|
|
|
|
# If we have a dollar sign, it introduces parameter |
5680
|
|
|
|
|
|
|
# substitution, a non trivial endeavor. |
5681
|
|
|
|
|
|
|
|
5682
|
|
|
|
|
|
|
} elsif ( $char eq '$' && $inx < $len ) { |
5683
|
72
|
|
|
|
|
153
|
my $name = substr $buffer, $inx++, 1; |
5684
|
72
|
|
|
|
|
117
|
my $brkt; |
5685
|
|
|
|
|
|
|
|
5686
|
|
|
|
|
|
|
# Names beginning with brackets are special. We note the |
5687
|
|
|
|
|
|
|
# fact and scan for the matching close bracket, throwing |
5688
|
|
|
|
|
|
|
# an exception if we do not have one. |
5689
|
|
|
|
|
|
|
|
5690
|
72
|
100
|
66
|
|
|
331
|
if ($name eq '{' && $inx < $len) { |
|
|
100
|
|
|
|
|
|
5691
|
34
|
|
|
|
|
52
|
$brkt = 1; |
5692
|
34
|
|
|
|
|
64
|
$name = ''; |
5693
|
34
|
|
|
|
|
49
|
my $nest = 1; |
5694
|
34
|
|
|
|
|
102
|
while ($inx < $len) { |
5695
|
369
|
|
|
|
|
566
|
$char = substr $buffer, $inx++, 1; |
5696
|
369
|
50
|
|
|
|
735
|
if ($char eq '{') { |
|
|
100
|
|
|
|
|
|
5697
|
0
|
|
|
|
|
0
|
$nest++; |
5698
|
|
|
|
|
|
|
} elsif ($char eq '}') { |
5699
|
33
|
50
|
|
|
|
80
|
--$nest or last; |
5700
|
|
|
|
|
|
|
} |
5701
|
336
|
|
|
|
|
553
|
$name .= $char; |
5702
|
|
|
|
|
|
|
} |
5703
|
34
|
100
|
|
|
|
92
|
$char eq '}' |
5704
|
|
|
|
|
|
|
or $self->wail('Missing right curly bracket'); |
5705
|
|
|
|
|
|
|
|
5706
|
|
|
|
|
|
|
# If the name begins with an alpha or an underscore, we |
5707
|
|
|
|
|
|
|
# simply append any word ('\w') characters to it. If it |
5708
|
|
|
|
|
|
|
# the word characters are immediately followed by a dot |
5709
|
|
|
|
|
|
|
# and more word characters we grab them too, and advance |
5710
|
|
|
|
|
|
|
# the current location past whatever we grabbed. The dot |
5711
|
|
|
|
|
|
|
# syntax is in aid of accessing attributes of |
5712
|
|
|
|
|
|
|
# attributes (e.g. $formatter.time_format) |
5713
|
|
|
|
|
|
|
|
5714
|
|
|
|
|
|
|
} elsif ( $name =~ m/ \A [[:alpha:]_] \z /smx ) { |
5715
|
21
|
|
|
|
|
102
|
pos( $buffer ) = $inx; |
5716
|
21
|
50
|
|
|
|
417
|
if ( $buffer =~ m/ \G ( \w* (?: [.] \w+ )? ) /smxgc ) { |
5717
|
21
|
|
|
|
|
64
|
$name .= $1; |
5718
|
21
|
|
|
|
|
45
|
$inx += length $1; |
5719
|
|
|
|
|
|
|
} |
5720
|
|
|
|
|
|
|
} |
5721
|
|
|
|
|
|
|
|
5722
|
|
|
|
|
|
|
# Only bracketed names can be indirected, and then only |
5723
|
|
|
|
|
|
|
# if the first character is a bang. |
5724
|
|
|
|
|
|
|
|
5725
|
71
|
|
|
|
|
112
|
my ($indirect, $value); |
5726
|
71
|
100
|
|
|
|
181
|
$brkt and $indirect = $name =~ s/ \A ! //smx; |
5727
|
|
|
|
|
|
|
|
5728
|
|
|
|
|
|
|
# If we find a colon and/or one of the other cabbalistic |
5729
|
|
|
|
|
|
|
# characters, we need to do some default processing. |
5730
|
|
|
|
|
|
|
|
5731
|
71
|
100
|
|
|
|
377
|
if ($name =~ m/ (.*?) ( [:]? [\-\+\=\?] | [:] ) (.*) /smx) { |
5732
|
28
|
|
|
|
|
134
|
my ($name, $flag, $rest) = ($1, $2, $3); |
5733
|
|
|
|
|
|
|
|
5734
|
|
|
|
|
|
|
# First we do indirection if that was required. |
5735
|
|
|
|
|
|
|
|
5736
|
28
|
50
|
|
|
|
66
|
$indirect |
5737
|
|
|
|
|
|
|
and $name = $self->_tokenize_var( |
5738
|
|
|
|
|
|
|
$name, $args, $relquote, $indirect); |
5739
|
|
|
|
|
|
|
|
5740
|
|
|
|
|
|
|
# Next we find out whether we have an honest-to-God |
5741
|
|
|
|
|
|
|
# colon, since that might specify substring |
5742
|
|
|
|
|
|
|
# processing. |
5743
|
|
|
|
|
|
|
|
5744
|
|
|
|
|
|
|
## my $colon = $flag =~ s/ \A : //smx ? ':' : ''; |
5745
|
28
|
|
|
|
|
98
|
$flag =~ s/ \A : //smx; |
5746
|
|
|
|
|
|
|
|
5747
|
|
|
|
|
|
|
# We run the stuff after the first cabbalistic |
5748
|
|
|
|
|
|
|
# character through the tokenizer, since further |
5749
|
|
|
|
|
|
|
# expansion is possible here. |
5750
|
|
|
|
|
|
|
|
5751
|
28
|
|
|
|
|
153
|
my $mod = __tokenize( |
5752
|
|
|
|
|
|
|
$self, |
5753
|
|
|
|
|
|
|
{ single => 1, noredirect => 1, in => $in }, |
5754
|
|
|
|
|
|
|
$rest, $args); |
5755
|
28
|
|
|
|
|
89
|
chomp $mod; # Don't want trailing \n here. |
5756
|
|
|
|
|
|
|
|
5757
|
|
|
|
|
|
|
# At long last we get the actual value of the |
5758
|
|
|
|
|
|
|
# variable. This will be either undef, a scalar, or |
5759
|
|
|
|
|
|
|
# a list reference. |
5760
|
|
|
|
|
|
|
|
5761
|
28
|
|
|
|
|
86
|
$value = $self->_tokenize_var( |
5762
|
|
|
|
|
|
|
$name, $args, $relquote); |
5763
|
|
|
|
|
|
|
|
5764
|
|
|
|
|
|
|
# The value is logically defined if it is a scalar |
5765
|
|
|
|
|
|
|
# and not undef, or if it is an array reference and |
5766
|
|
|
|
|
|
|
# the array is not empty. |
5767
|
|
|
|
|
|
|
|
5768
|
28
|
100
|
|
|
|
78
|
my $defined = ref $value ? @$value : defined $value; |
5769
|
|
|
|
|
|
|
|
5770
|
|
|
|
|
|
|
# The '+' cabbalistic sign replaces the value of the |
5771
|
|
|
|
|
|
|
# variable if it is logically defined. |
5772
|
|
|
|
|
|
|
|
5773
|
28
|
100
|
|
|
|
125
|
if ($flag eq '+') { |
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
5774
|
4
|
100
|
|
|
|
19
|
$value = $defined ? $mod : ''; |
5775
|
|
|
|
|
|
|
|
5776
|
|
|
|
|
|
|
# If the variable is defined, only substring |
5777
|
|
|
|
|
|
|
# processing is possible. This actually is |
5778
|
|
|
|
|
|
|
# implemented as slice processing if the value is an |
5779
|
|
|
|
|
|
|
# array reference. |
5780
|
|
|
|
|
|
|
|
5781
|
|
|
|
|
|
|
} elsif ($defined) { |
5782
|
16
|
100
|
|
|
|
39
|
if ($flag eq '') { |
5783
|
10
|
|
|
|
|
59
|
my @pos = split ':', $mod, 2; |
5784
|
10
|
|
|
|
|
26
|
foreach ( @pos ) { |
5785
|
18
|
|
|
|
|
57
|
s/ \A \s+ //smx; |
5786
|
|
|
|
|
|
|
} |
5787
|
10
|
50
|
|
|
|
32
|
@pos > 2 |
5788
|
|
|
|
|
|
|
and $self->wail( |
5789
|
|
|
|
|
|
|
'Substring expansion has extra arguments' ); |
5790
|
10
|
|
|
|
|
26
|
foreach ( @pos ) { |
5791
|
18
|
50
|
|
|
|
75
|
m/ \A [-+]? [0-9]+ \z /smx |
5792
|
|
|
|
|
|
|
or $self->wail( |
5793
|
|
|
|
|
|
|
'Substring expansion argument non-numeric' |
5794
|
|
|
|
|
|
|
); |
5795
|
|
|
|
|
|
|
} |
5796
|
10
|
100
|
|
|
|
25
|
if (ref $value) { |
5797
|
4
|
50
|
|
|
|
9
|
if (@pos > 1) { |
5798
|
4
|
|
|
|
|
20
|
$pos[1] += $pos[0] - 1; |
5799
|
|
|
|
|
|
|
} else { |
5800
|
0
|
|
|
|
|
0
|
$pos[1] = $#$args; |
5801
|
|
|
|
|
|
|
} |
5802
|
4
|
100
|
|
|
|
13
|
$pos[1] > $#$value and $pos[1] = $#$value; |
5803
|
4
|
|
|
|
|
16
|
$value = [@$value[$pos[0] .. $pos[1]]]; |
5804
|
|
|
|
|
|
|
} else { |
5805
|
|
|
|
|
|
|
# We want to disable warnings if we slop |
5806
|
|
|
|
|
|
|
# outside the string. |
5807
|
20
|
|
|
20
|
|
227
|
no warnings qw{substr}; |
|
20
|
|
|
|
|
52
|
|
|
20
|
|
|
|
|
49111
|
|
5808
|
6
|
100
|
|
|
|
31
|
$value = @pos == 1 ? substr $value, $pos[0] : |
5809
|
|
|
|
|
|
|
substr $value, $pos[0], $pos[1]; |
5810
|
|
|
|
|
|
|
} |
5811
|
|
|
|
|
|
|
} |
5812
|
|
|
|
|
|
|
|
5813
|
|
|
|
|
|
|
# If the cabbalistic sign is '-', we supply the |
5814
|
|
|
|
|
|
|
# remainder of the specification as the default. |
5815
|
|
|
|
|
|
|
|
5816
|
|
|
|
|
|
|
} elsif ($flag eq '-') { |
5817
|
2
|
|
|
|
|
6
|
$value = $mod; |
5818
|
|
|
|
|
|
|
|
5819
|
|
|
|
|
|
|
# If the cabbalistic sign is '=', we supply the |
5820
|
|
|
|
|
|
|
# remainder of the specification as the default. We |
5821
|
|
|
|
|
|
|
# also set the variable to the value, for future |
5822
|
|
|
|
|
|
|
# use. Note that special variables may not be set, |
5823
|
|
|
|
|
|
|
# and result in an exception. |
5824
|
|
|
|
|
|
|
|
5825
|
|
|
|
|
|
|
} elsif ($flag eq '=') { |
5826
|
3
|
|
|
|
|
6
|
$value = $mod; |
5827
|
3
|
50
|
33
|
|
|
71
|
if ( $special{$name} || $name !~ m/ \D /smx ) { |
|
|
50
|
|
|
|
|
|
5828
|
0
|
|
|
|
|
0
|
$self->wail("Cannot assign to \$$name"); |
5829
|
|
|
|
|
|
|
## } elsif ($name !~ m/\D/) { |
5830
|
|
|
|
|
|
|
## $args->[$name - 1] = $value; |
5831
|
|
|
|
|
|
|
} elsif (exists $mutator{$name}) { |
5832
|
0
|
|
|
|
|
0
|
$self->set($name => $value); |
5833
|
|
|
|
|
|
|
} else { |
5834
|
3
|
|
|
|
|
28
|
$self->{frame}[-1]{define}{$name} = $value; |
5835
|
|
|
|
|
|
|
} |
5836
|
|
|
|
|
|
|
|
5837
|
|
|
|
|
|
|
# If the cabbalistic sign is '?', we throw an |
5838
|
|
|
|
|
|
|
# exception with the remainder of the specification |
5839
|
|
|
|
|
|
|
# as the text. |
5840
|
|
|
|
|
|
|
|
5841
|
|
|
|
|
|
|
} elsif ($flag eq '?') { |
5842
|
2
|
|
|
|
|
9
|
$self->wail($mod); |
5843
|
|
|
|
|
|
|
|
5844
|
|
|
|
|
|
|
# If there is no cabbalistic sign at all, we fell |
5845
|
|
|
|
|
|
|
# through here trying to do substring expansion on |
5846
|
|
|
|
|
|
|
# an undefined variable. Since Bash allows this, we |
5847
|
|
|
|
|
|
|
# will to, though with misgivings. |
5848
|
|
|
|
|
|
|
|
5849
|
|
|
|
|
|
|
} elsif ( $flag eq '' ) { |
5850
|
1
|
|
|
|
|
2
|
$value = ''; |
5851
|
|
|
|
|
|
|
|
5852
|
|
|
|
|
|
|
# Given the way the parser works, the above should |
5853
|
|
|
|
|
|
|
# have exhausted all possibilities. But being a |
5854
|
|
|
|
|
|
|
# cautious programmer ... |
5855
|
|
|
|
|
|
|
|
5856
|
|
|
|
|
|
|
} else { |
5857
|
0
|
|
|
|
|
0
|
$self->weep( |
5858
|
|
|
|
|
|
|
"\$flag = '$flag'. This should not happen" |
5859
|
|
|
|
|
|
|
); |
5860
|
|
|
|
|
|
|
} |
5861
|
|
|
|
|
|
|
|
5862
|
|
|
|
|
|
|
# Without any cabbalistic signs, variable expansion is |
5863
|
|
|
|
|
|
|
# easy. We perform the indirection if needed, and then |
5864
|
|
|
|
|
|
|
# grab the value of the variable, which still can be |
5865
|
|
|
|
|
|
|
# undef, a scalar, or an array reference. |
5866
|
|
|
|
|
|
|
|
5867
|
|
|
|
|
|
|
} else { |
5868
|
43
|
100
|
|
|
|
108
|
$indirect |
5869
|
|
|
|
|
|
|
and $name = $self->_tokenize_var( |
5870
|
|
|
|
|
|
|
$name, $args, $relquote, $indirect); |
5871
|
43
|
|
|
|
|
127
|
$value = $self->_tokenize_var( |
5872
|
|
|
|
|
|
|
$name, $args, $relquote); |
5873
|
|
|
|
|
|
|
} |
5874
|
|
|
|
|
|
|
|
5875
|
|
|
|
|
|
|
# For simplicity in what follows, make the value into an |
5876
|
|
|
|
|
|
|
# array reference. |
5877
|
69
|
100
|
|
|
|
232
|
ref $value |
|
|
100
|
|
|
|
|
|
5878
|
|
|
|
|
|
|
or $value = defined $value ? [ $value ] : []; |
5879
|
|
|
|
|
|
|
|
5880
|
|
|
|
|
|
|
# If we are inside quotes |
5881
|
69
|
100
|
|
|
|
151
|
if ( $relquote ) { |
5882
|
|
|
|
|
|
|
# do case modification |
5883
|
|
|
|
|
|
|
# NOTE that the argument list is modified in-place. |
5884
|
12
|
|
|
|
|
19
|
$self->_case_mod( @{ $value } ); |
|
12
|
|
|
|
|
37
|
|
5885
|
|
|
|
|
|
|
} else { |
5886
|
|
|
|
|
|
|
# otherwise do word splitting |
5887
|
57
|
|
|
|
|
77
|
$value = [ map { split qr{ \s+ }smx } @{ $value } ]; |
|
71
|
|
|
|
|
434
|
|
|
57
|
|
|
|
|
122
|
|
5888
|
|
|
|
|
|
|
} |
5889
|
|
|
|
|
|
|
|
5890
|
|
|
|
|
|
|
# If we have a value, append each element to the current |
5891
|
|
|
|
|
|
|
# token, and then create a new token for the next |
5892
|
|
|
|
|
|
|
# element. The last element's empty token gets |
5893
|
|
|
|
|
|
|
# discarded, since we may need to append more data to |
5894
|
|
|
|
|
|
|
# the last element (e.g. "$@ foo"). |
5895
|
69
|
100
|
|
|
|
141
|
if ( @{ $value } ) { |
|
69
|
|
|
|
|
160
|
|
5896
|
58
|
|
|
|
|
141
|
foreach ( @$value ) { |
5897
|
86
|
|
|
|
|
186
|
$rslt[-1]{token} .= $_; |
5898
|
86
|
|
|
|
|
181
|
push @rslt, {}; |
5899
|
|
|
|
|
|
|
} |
5900
|
58
|
|
|
|
|
112
|
pop @rslt; |
5901
|
|
|
|
|
|
|
} |
5902
|
|
|
|
|
|
|
|
5903
|
|
|
|
|
|
|
# Here ends the variable expansion code. |
5904
|
|
|
|
|
|
|
|
5905
|
|
|
|
|
|
|
# If the character is an angle bracket or a pipe, we have a |
5906
|
|
|
|
|
|
|
# redirect specification. This always starts a new token. We |
5907
|
|
|
|
|
|
|
# flag the token as a redirect, stuff all matching |
5908
|
|
|
|
|
|
|
# characters into the mode (throwing an exception if there |
5909
|
|
|
|
|
|
|
# are too many), consume any trailing spaces, and set the |
5910
|
|
|
|
|
|
|
# token value to the empty string to prevent executing this |
5911
|
|
|
|
|
|
|
# code again when we hit the first character of the file |
5912
|
|
|
|
|
|
|
# name. Note that redirect tokens always get tilde |
5913
|
|
|
|
|
|
|
# expansion. |
5914
|
|
|
|
|
|
|
|
5915
|
|
|
|
|
|
|
} elsif ( $char =~ m/ [<>|] /smx ) { |
5916
|
6
|
100
|
|
|
|
58
|
push @rslt, { |
|
|
50
|
|
|
|
|
|
5917
|
|
|
|
|
|
|
redirect => 1, |
5918
|
|
|
|
|
|
|
type => ($char eq '<' ? '<' : '>'), |
5919
|
|
|
|
|
|
|
mode => ($char eq '|' ? '|-' : $char), |
5920
|
|
|
|
|
|
|
expand => ($char ne '|') |
5921
|
|
|
|
|
|
|
}; |
5922
|
6
|
|
|
|
|
32
|
while ($inx < $len) { |
5923
|
11
|
|
|
|
|
25
|
my $next = substr $buffer, $inx++, 1; |
5924
|
11
|
50
|
|
|
|
29
|
$next =~ m/ \s /smx and next; |
5925
|
11
|
100
|
|
|
|
25
|
if ($next eq $char) { |
5926
|
6
|
|
|
|
|
18
|
$rslt[-1]{mode} .= $next; |
5927
|
6
|
100
|
|
|
|
26
|
length $rslt[-1]{mode} > 2 |
5928
|
|
|
|
|
|
|
and $self->wail( |
5929
|
|
|
|
|
|
|
"Syntax error near $rslt[-1]{mode}"); |
5930
|
|
|
|
|
|
|
} else { |
5931
|
5
|
|
|
|
|
18
|
--$inx; |
5932
|
5
|
|
|
|
|
16
|
$rslt[-1]{token} = ''; |
5933
|
5
|
|
|
|
|
13
|
last; |
5934
|
|
|
|
|
|
|
} |
5935
|
|
|
|
|
|
|
} |
5936
|
5
|
100
|
|
|
|
16
|
if ( '<<' eq $rslt[-1]{mode} ) { # Heredoc |
5937
|
4
|
|
|
|
|
9
|
delete $rslt[-1]{redirect}; |
5938
|
4
|
|
|
|
|
7
|
delete $rslt[-1]{type}; |
5939
|
4
|
|
|
|
|
7
|
delete $rslt[-1]{mode}; |
5940
|
4
|
|
|
|
|
9
|
my $quote = ''; |
5941
|
4
|
|
|
|
|
11
|
while ( $inx < $len ) { |
5942
|
62
|
|
|
|
|
96
|
my $next = substr $buffer, $inx++, 1; |
5943
|
62
|
100
|
|
|
|
112
|
if ( $next =~ m/ \s /smx ) { |
5944
|
2
|
50
|
|
|
|
7
|
$quote or last; |
5945
|
0
|
|
|
|
|
0
|
$rslt[-1]{token} .= $next; |
5946
|
|
|
|
|
|
|
} else { |
5947
|
|
|
|
|
|
|
'' eq $rslt[-1]{token} |
5948
|
|
|
|
|
|
|
and $next =~ m/ ['"] /smx |
5949
|
|
|
|
|
|
|
and $quote = $next |
5950
|
60
|
100
|
100
|
|
|
146
|
or $rslt[-1]{token} .= $next; |
|
|
|
66
|
|
|
|
|
5951
|
|
|
|
|
|
|
$quote |
5952
|
|
|
|
|
|
|
and $next eq $quote |
5953
|
60
|
100
|
100
|
|
|
172
|
and $rslt[-1]{token} ne '' |
|
|
|
100
|
|
|
|
|
5954
|
|
|
|
|
|
|
and last; |
5955
|
|
|
|
|
|
|
} |
5956
|
|
|
|
|
|
|
} |
5957
|
4
|
100
|
|
|
|
15
|
$quote and $rslt[-1]{token} =~ s/ . \z //sxm; |
5958
|
4
|
|
|
|
|
8
|
my $terminator = $rslt[-1]{token}; |
5959
|
4
|
|
|
|
|
8
|
my $look_for = $terminator . "\n"; |
5960
|
4
|
|
|
|
|
14
|
$rslt[-1]{token} = ''; |
5961
|
4
|
|
|
|
|
10
|
$rslt[-1]{expand} = $quote ne q<'>; |
5962
|
4
|
|
|
|
|
6
|
while ( 1 ) { |
5963
|
9
|
|
|
|
|
37
|
my $buffer = $self->_read_continuation( $in, |
5964
|
|
|
|
|
|
|
"Here doc terminator $terminator not found" ); |
5965
|
9
|
100
|
|
|
|
27
|
$buffer eq $look_for and last; |
5966
|
5
|
|
|
|
|
13
|
$rslt[-1]{token} .= $buffer; |
5967
|
|
|
|
|
|
|
} |
5968
|
4
|
100
|
|
|
|
26
|
if ( $quote ne q<'> ) { |
5969
|
|
|
|
|
|
|
$rslt[-1]{token} = __tokenize( |
5970
|
|
|
|
|
|
|
$self, |
5971
|
|
|
|
|
|
|
{ single => 1, noredirect => 1, in => $in }, |
5972
|
3
|
|
|
|
|
41
|
$rslt[-1]{token}, $args |
5973
|
|
|
|
|
|
|
); |
5974
|
|
|
|
|
|
|
} |
5975
|
4
|
|
|
|
|
13
|
push @rslt, {}; # New token |
5976
|
|
|
|
|
|
|
} |
5977
|
|
|
|
|
|
|
|
5978
|
|
|
|
|
|
|
# If the token already exists at this point, the current |
5979
|
|
|
|
|
|
|
# character, whatever it is, is simply appended to it. |
5980
|
|
|
|
|
|
|
|
5981
|
|
|
|
|
|
|
} elsif (exists $rslt[-1]{token} || $relquote) { |
5982
|
|
|
|
|
|
|
# do case modification |
5983
|
|
|
|
|
|
|
# NOTE that the argument list is modified in-place. |
5984
|
3744
|
|
|
|
|
8920
|
$self->_case_mod( $char ); |
5985
|
3744
|
|
|
|
|
5747
|
$rslt[-1]{token} .= $char; |
5986
|
|
|
|
|
|
|
|
5987
|
|
|
|
|
|
|
# If the character is a tilde, we flag the token for tilde |
5988
|
|
|
|
|
|
|
# expansion. |
5989
|
|
|
|
|
|
|
|
5990
|
|
|
|
|
|
|
} elsif ($char eq '~') { |
5991
|
12
|
|
|
|
|
56
|
$rslt[-1]{tilde}++; |
5992
|
12
|
|
|
|
|
45
|
$rslt[-1]{token} .= $char; |
5993
|
|
|
|
|
|
|
|
5994
|
|
|
|
|
|
|
# If the character is a hash mark, it means a comment. Bail |
5995
|
|
|
|
|
|
|
# out of the loop. |
5996
|
|
|
|
|
|
|
} elsif ( $char eq '#' ) { |
5997
|
2
|
|
|
|
|
4
|
last; |
5998
|
|
|
|
|
|
|
|
5999
|
|
|
|
|
|
|
# Else we just put it in the token. |
6000
|
|
|
|
|
|
|
} else { |
6001
|
829
|
|
|
|
|
2040
|
$rslt[-1]{token} .= $char; |
6002
|
|
|
|
|
|
|
} |
6003
|
|
|
|
|
|
|
|
6004
|
|
|
|
|
|
|
# If we're at the end of the buffer but we're inside quotes, |
6005
|
|
|
|
|
|
|
# we need to read another line. |
6006
|
6305
|
100
|
66
|
|
|
15963
|
if ( $inx >= $len && ( $absquote || $relquote ) ) { |
|
|
|
100
|
|
|
|
|
6007
|
2
|
50
|
|
|
|
7
|
$buffer .= $self->_read_continuation( $in, |
6008
|
|
|
|
|
|
|
$absquote ? 'Unclosed single quote' : |
6009
|
|
|
|
|
|
|
'Unclosed double quote' |
6010
|
|
|
|
|
|
|
); |
6011
|
2
|
|
|
|
|
5
|
$len = length $buffer; |
6012
|
|
|
|
|
|
|
} |
6013
|
|
|
|
|
|
|
|
6014
|
|
|
|
|
|
|
} |
6015
|
|
|
|
|
|
|
|
6016
|
|
|
|
|
|
|
# We have run through the entire string to be tokenized. If |
6017
|
|
|
|
|
|
|
# there are unclosed quotes of either sort, we declare an error |
6018
|
|
|
|
|
|
|
# here. This should actually not happen, since we allow |
6019
|
|
|
|
|
|
|
# multi-line quotes, and if we have run out of input we catch it |
6020
|
|
|
|
|
|
|
# above. |
6021
|
|
|
|
|
|
|
|
6022
|
376
|
50
|
|
|
|
798
|
$absquote and $self->wail( 'Unclosed terminal single quote' ); |
6023
|
376
|
50
|
|
|
|
832
|
$relquote and $self->wail( 'Unclosed terminal double quote' ); |
6024
|
|
|
|
|
|
|
|
6025
|
|
|
|
|
|
|
# Replace leading punctuation with the corresponding method. |
6026
|
|
|
|
|
|
|
|
6027
|
|
|
|
|
|
|
shift @rslt |
6028
|
376
|
|
100
|
|
|
1520
|
while @rslt && ! defined $rslt[0]{token}; |
6029
|
376
|
50
|
66
|
|
|
2752
|
if ( defined $rslt[0]{token} and |
6030
|
|
|
|
|
|
|
$rslt[0]{token} =~ s/ \A ( $command_equiv_re ) //smx ) { |
6031
|
0
|
0
|
|
|
|
0
|
if ( $rslt[0]{token} eq '' ) { |
|
|
0
|
|
|
|
|
|
6032
|
0
|
|
|
|
|
0
|
$rslt[0]{token} = $command_equivalent{$1}; |
6033
|
|
|
|
|
|
|
} elsif ( $opt->{single} ) { |
6034
|
|
|
|
|
|
|
$rslt[0]{token} = join ' ', $command_equivalent{$1}, |
6035
|
0
|
|
|
|
|
0
|
$rslt[0]{token}; |
6036
|
|
|
|
|
|
|
} else { |
6037
|
|
|
|
|
|
|
unshift @rslt, { |
6038
|
0
|
|
|
|
|
0
|
token => $command_equivalent{$1}, |
6039
|
|
|
|
|
|
|
}; |
6040
|
|
|
|
|
|
|
} |
6041
|
|
|
|
|
|
|
} |
6042
|
|
|
|
|
|
|
|
6043
|
|
|
|
|
|
|
# Go through our prospective tokens, keeping only those that |
6044
|
|
|
|
|
|
|
# were actually defined, and shuffling the redirects off into |
6045
|
|
|
|
|
|
|
# the redirect hash. |
6046
|
|
|
|
|
|
|
|
6047
|
376
|
|
|
|
|
807
|
my (@tokens, %redir); |
6048
|
376
|
|
|
|
|
616
|
my $expand_tildes = 1; |
6049
|
376
|
100
|
100
|
|
|
3228
|
if ( defined $rslt[0]{token} |
6050
|
|
|
|
|
|
|
and my $kode = $self->can( $rslt[0]{token} ) ) { |
6051
|
252
|
100
|
|
|
|
867
|
if ( my $hash = $self->__get_attr( $kode, 'Tokenize' ) ) { |
6052
|
2
|
|
|
|
|
16
|
$expand_tildes = $hash->{expand_tilde}; |
6053
|
|
|
|
|
|
|
} |
6054
|
|
|
|
|
|
|
} |
6055
|
376
|
|
|
|
|
906
|
foreach (@rslt) { |
6056
|
1318
|
100
|
|
|
|
2657
|
exists $_->{token} or next; |
6057
|
966
|
100
|
66
|
|
|
2699
|
if ($_->{redirect}) { |
|
|
100
|
|
|
|
|
|
6058
|
1
|
50
|
|
|
|
6
|
if ( $_->{mode} eq '<' ) { |
6059
|
|
|
|
|
|
|
push @tokens, $self->_file_reader( |
6060
|
0
|
|
|
|
|
0
|
$_->{token}, { glob => 1 } ); |
6061
|
|
|
|
|
|
|
} else { |
6062
|
1
|
|
|
|
|
3
|
my $type = $_->{type}; |
6063
|
|
|
|
|
|
|
$redir{$type} = { |
6064
|
|
|
|
|
|
|
mode => $_->{mode}, |
6065
|
|
|
|
|
|
|
name => ($_->{expand} ? |
6066
|
|
|
|
|
|
|
$self->expand_tilde($_->{token}) : |
6067
|
1
|
50
|
|
|
|
13
|
$_->{token}), |
6068
|
|
|
|
|
|
|
}; |
6069
|
|
|
|
|
|
|
} |
6070
|
|
|
|
|
|
|
} elsif ( $expand_tildes && $_->{tilde} ) { |
6071
|
12
|
|
|
|
|
80
|
push @tokens, $self->expand_tilde( $_->{token} ); |
6072
|
|
|
|
|
|
|
} else { |
6073
|
953
|
|
|
|
|
2003
|
push @tokens, $_->{token}; |
6074
|
|
|
|
|
|
|
} |
6075
|
|
|
|
|
|
|
} |
6076
|
|
|
|
|
|
|
|
6077
|
|
|
|
|
|
|
# With the {single} and {noredirect} options both asserted, |
6078
|
|
|
|
|
|
|
# there is only one token, so we return it directly. |
6079
|
|
|
|
|
|
|
|
6080
|
372
|
50
|
66
|
|
|
985
|
($opt->{single} && $opt->{noredirect}) and return $tokens[0]; |
6081
|
|
|
|
|
|
|
|
6082
|
|
|
|
|
|
|
# With the {noredirect} option asserted, we just return a |
6083
|
|
|
|
|
|
|
# reference to the tokens found. |
6084
|
|
|
|
|
|
|
|
6085
|
341
|
50
|
|
|
|
702
|
$opt->{noredirect} and return \@tokens; |
6086
|
|
|
|
|
|
|
|
6087
|
|
|
|
|
|
|
# Otherwise we return a list, with a reference to the token list |
6088
|
|
|
|
|
|
|
# as the first element, and a reference to the redirect hash as |
6089
|
|
|
|
|
|
|
# the second element. |
6090
|
|
|
|
|
|
|
|
6091
|
341
|
|
|
|
|
2185
|
return (\@tokens, \%redir); |
6092
|
|
|
|
|
|
|
} |
6093
|
|
|
|
|
|
|
|
6094
|
|
|
|
|
|
|
# Retrieve the value of a variable. |
6095
|
|
|
|
|
|
|
sub _tokenize_var { |
6096
|
74
|
|
|
74
|
|
343
|
my ($self, $name, $args, $relquote, $indirect) = @_; |
6097
|
|
|
|
|
|
|
|
6098
|
74
|
0
|
33
|
|
|
294
|
defined $name and $name ne '' |
|
|
50
|
|
|
|
|
|
6099
|
|
|
|
|
|
|
or return $indirect ? '' : undef; |
6100
|
|
|
|
|
|
|
|
6101
|
74
|
100
|
|
|
|
196
|
$special{$name} and do { |
6102
|
19
|
|
|
|
|
80
|
my $val = $special{$name}->($args, $relquote); |
6103
|
19
|
50
|
33
|
|
|
82
|
return ($indirect && ref $val) ? '' : $val; |
6104
|
|
|
|
|
|
|
}; |
6105
|
|
|
|
|
|
|
|
6106
|
55
|
100
|
|
|
|
207
|
$name !~ m/ \D /smx |
6107
|
|
|
|
|
|
|
and return $args->[$name - 1]; |
6108
|
|
|
|
|
|
|
|
6109
|
40
|
|
|
|
|
114
|
my $value = $self->_attribute_value( $name ); |
6110
|
40
|
100
|
|
|
|
133
|
NULL_REF eq ref $value |
6111
|
|
|
|
|
|
|
or return $value; |
6112
|
|
|
|
|
|
|
|
6113
|
|
|
|
|
|
|
exists $self->{exported}{$name} |
6114
|
34
|
100
|
|
|
|
100
|
and return $self->{exported}{$name}; |
6115
|
|
|
|
|
|
|
|
6116
|
|
|
|
|
|
|
defined $ENV{$name} |
6117
|
32
|
100
|
|
|
|
132
|
and return $ENV{$name}; |
6118
|
|
|
|
|
|
|
|
6119
|
14
|
|
|
|
|
37
|
foreach my $frame ( reverse @{ $self->{frame} } ) { |
|
14
|
|
|
|
|
54
|
|
6120
|
|
|
|
|
|
|
defined $frame->{define}{$name} |
6121
|
17
|
100
|
|
|
|
69
|
and return $frame->{define}{$name}; |
6122
|
|
|
|
|
|
|
} |
6123
|
|
|
|
|
|
|
|
6124
|
11
|
|
|
|
|
26
|
return; |
6125
|
|
|
|
|
|
|
} |
6126
|
|
|
|
|
|
|
|
6127
|
|
|
|
|
|
|
} |
6128
|
|
|
|
|
|
|
|
6129
|
|
|
|
|
|
|
# Apply case modification to the arguments |
6130
|
|
|
|
|
|
|
# NOTE that the argument list is modified in-place. I'm a little |
6131
|
|
|
|
|
|
|
# surprised that this didn't tickle Perl::Critic. |
6132
|
|
|
|
|
|
|
sub _case_mod { |
6133
|
3756
|
|
|
3756
|
|
5238
|
my $self = shift; |
6134
|
3756
|
|
|
|
|
5887
|
foreach ( @_ ) { |
6135
|
|
|
|
|
|
|
$self->{_case_mod}{case} |
6136
|
3759
|
100
|
|
|
|
7144
|
and $_ = $self->{_case_mod}{case}->( $self, $_ ); |
6137
|
3759
|
|
|
|
|
4969
|
my $code; |
6138
|
|
|
|
|
|
|
$code = delete $self->{_case_mod}{single} |
6139
|
3759
|
100
|
|
|
|
7739
|
and $_ = $code->( $self, $_ ); |
6140
|
|
|
|
|
|
|
} |
6141
|
3756
|
|
|
|
|
5512
|
return; |
6142
|
|
|
|
|
|
|
} |
6143
|
|
|
|
|
|
|
|
6144
|
|
|
|
|
|
|
# $self->wail(...) |
6145
|
|
|
|
|
|
|
# |
6146
|
|
|
|
|
|
|
# Either die or croak with the arguments, depending on the value |
6147
|
|
|
|
|
|
|
# of the 'warning' attribute. If we die, a trailing period and |
6148
|
|
|
|
|
|
|
# newline are provided if necessary. If we croak, any trailing |
6149
|
|
|
|
|
|
|
# punctuation and newline are stripped. |
6150
|
|
|
|
|
|
|
|
6151
|
|
|
|
|
|
|
sub wail { |
6152
|
18
|
|
|
18
|
1
|
79
|
my ($self, @args) = @_; |
6153
|
18
|
|
|
|
|
194
|
$self->{_warner}->wail( @args ); |
6154
|
0
|
|
|
|
|
0
|
return; # We can't hit this, but Perl::Critic does not know that. |
6155
|
|
|
|
|
|
|
} |
6156
|
|
|
|
|
|
|
|
6157
|
|
|
|
|
|
|
# $self->__wail(...) |
6158
|
|
|
|
|
|
|
# |
6159
|
|
|
|
|
|
|
# either wail() or whinge() depending on error_out. |
6160
|
|
|
|
|
|
|
sub __wail { |
6161
|
1
|
|
|
1
|
|
4
|
my ($self, @args) = @_; |
6162
|
1
|
50
|
|
|
|
3
|
if ( $self->get( 'error_out' ) ) { |
6163
|
1
|
|
|
|
|
12
|
$self->{_warner}->wail( @args ); |
6164
|
|
|
|
|
|
|
} else { |
6165
|
0
|
|
|
|
|
0
|
$self->{_warner}->whinge( @args ); |
6166
|
|
|
|
|
|
|
} |
6167
|
0
|
|
|
|
|
0
|
return; |
6168
|
|
|
|
|
|
|
} |
6169
|
|
|
|
|
|
|
|
6170
|
|
|
|
|
|
|
# $self->weep(...) |
6171
|
|
|
|
|
|
|
# |
6172
|
|
|
|
|
|
|
# Die with a stack dump (Carp::confess). |
6173
|
|
|
|
|
|
|
|
6174
|
|
|
|
|
|
|
sub weep { |
6175
|
0
|
|
|
0
|
1
|
0
|
my ($self, @args) = @_; |
6176
|
0
|
|
|
|
|
0
|
$self->{_warner}->weep( @args ); |
6177
|
0
|
|
|
|
|
0
|
return; # We can't hit this, but Perl::Critic does not know that. |
6178
|
|
|
|
|
|
|
} |
6179
|
|
|
|
|
|
|
|
6180
|
|
|
|
|
|
|
# $self->whinge(...) |
6181
|
|
|
|
|
|
|
# |
6182
|
|
|
|
|
|
|
# Either warn or carp with the arguments, depending on the value |
6183
|
|
|
|
|
|
|
# of the 'warn' attribute. If we warn, a trailing period and |
6184
|
|
|
|
|
|
|
# newline are provided if necessary. If we carp, any trailing |
6185
|
|
|
|
|
|
|
# punctuation and newline are stripped. |
6186
|
|
|
|
|
|
|
|
6187
|
|
|
|
|
|
|
sub whinge { |
6188
|
3
|
|
|
3
|
1
|
10
|
my ($self, @args) = @_; |
6189
|
3
|
|
|
|
|
21
|
$self->{_warner}->whinge( @args ); |
6190
|
3
|
|
|
|
|
11
|
return; |
6191
|
|
|
|
|
|
|
} |
6192
|
|
|
|
|
|
|
|
6193
|
|
|
|
|
|
|
1; |
6194
|
|
|
|
|
|
|
|
6195
|
|
|
|
|
|
|
__END__ |