Astro-satpass

 view release on metacpan or  search on metacpan

script/satpass  view on Meta::CPAN

#!/usr/bin/env perl

package Astro::satpass;

use strict;
use warnings;

use Astro::Coord::ECI;
use Astro::Coord::ECI::Moon;
use Astro::Coord::ECI::Sun;
use Astro::Coord::ECI::Star;
use Astro::Coord::ECI::TLE qw{ :constants };
use Astro::Coord::ECI::TLE::Set;
use Astro::Coord::ECI::Utils qw{ :mainstream };

use Carp qw{confess};
use Config;
use Data::Dumper;
use File::Basename;
use FileHandle;
use Getopt::Long;
use Pod::Usage;
use POSIX qw{ floor };
use Text::Abbrev;
use Text::ParseWords;

{
    local $@ = undef;
    use constant HAVE_TLE_IRIDIUM	=> eval {
	require Astro::Coord::ECI::TLE::Iridium;
	1;
    } || 0;
}

my (
	$clipboard_unavailable,
	$io_string_unavailable,
    );
$clipboard_unavailable = $IO::Clipboard::clipboard_unavailable;

########################################################################
#
#	Initialization
#

our $VERSION = '0.135';

use constant LINFMT => <<eod;
%s %s %8.4f %9.4f %7.1f %-4s %s
eod

use constant LINFMT_MAG => <<eod;
%s %s %8.4f %9.4f %7.1f %4s %-4s %-4s
eod

use constant BGFMT => <<eod;
%s %s %8.4f %9.4f              %s
eod

use constant SUN_CLASS_DEFAULT	=> 'Astro::Coord::ECI::Sun';

my @bodies;
my @sky = (
    SUN_CLASS_DEFAULT->new (),
    Astro::Coord::ECI::Moon->new (),
);

my %opt;	# Options passed when we were invoked.
my %cmdconfig;	# How option parsing is to be comfigured for command.
my %cmdopt;	# Options for individual satpass commands.
my %cmdlgl;	# Legal options for a given command.
my %cmdquote;	# 1 if we keep quotes when parsing the command.

my %exported;	# True if the parameter is exported.
my %parm = (
##    almanac_horizon	=> 0, set below
    appulse => 0,
    autoheight => 1,
    background => 1,
    backdate => 1,
    country => 'us',
    date_format => '%a %d-%b-%Y',
    debug => 0,
    desired_equinox_dynamical => 0,
    echo => 0,
    edge_of_earths_shadow => 1,
    ellipsoid => Astro::Coord::ECI->get ('ellipsoid'),
    error_out => 0,
    exact_event => 1,
    explicit_macro_delete => 0,
    extinction => 1,
    flare_mag_day => -6,
    flare_mag_night => 0,
    geometric => 1,
    gmt => 0,
##    horizon => 20, set below
    illum	=> SUN_CLASS_DEFAULT,
    local_coord => 'azel_rng',
    model => 'model',

script/satpass  view on Meta::CPAN

    visible => \&_set_unmodified, # 1 = only if sun down & sat illuminated
    webcmd => \&_set_webcmd,	# Command to spawn for web pages
    );

my %accessor = (
    desired_equinox_dynamical => \&_get_time,
);
foreach (keys %mutator) {$accessor{$_} ||= \&_show_unmodified};

my @bearing = qw{N NE E SE S SW W NW};

my %twilight_def = (
    civil => deg2rad (-6),
    nautical => deg2rad (-12),
    astronomical => deg2rad (-18),
    );
my %twilight_abbr = abbrev (keys %twilight_def);

set( twilight	=> 'civil' );
set( horizon	=> 20 );
set( almanac_horizon => 0 );

my $inifn = $^O eq 'MSWin32' || $^O eq 'VMS' || $^O eq 'MacOS' ?
    'satpass.ini' : '.satpass';

my $inifil = $ENV{SATPASSINI} ? $ENV{SATPASSINI} :
    $^O eq 'VMS' ? "SYS\$LOGIN:$inifn" :
    $^O eq 'MacOS' ? $inifn :
    $ENV{HOME} ? "$ENV{HOME}/$inifn" :
    $ENV{LOGDIR} ? "$ENV{LOGDIR}/$inifn" :
    $ENV{USERPROFILE} ? "$ENV{USERPROFILE}/$inifn" : undef;

sub _format_location;	# Predeclare, so I do not need explicit STDOUT.
sub _time ();		# Predeclare, since I intend to redefine.

my $reader = eval {
    -t STDIN
	or return;
    require Term::ReadLine;
    my $rl = Term::ReadLine->new( 'Predict satellite passes' )
	or return;
    return sub {
	my ( $fh, @arg ) = @_;
	return -t $fh ?  $rl->readline( @arg ) : $fh->getline();
    };
} || sub {
    my ( $fh, @arg ) = @_;
    -t $fh and print "\n@arg";
    return $fh->getline();
};

my $fh = *STDIN;
my @frame;
my %alias = (
    '!' => 'system',
    '.' => 'source',
    bye => 'exit',
    quit => 'exit',
    );

GetOptions (\%opt, qw{clipboard filter initialization_file=s
    version}) or die <<eod;

Predict satellite visibility.

usage: perl @{[basename $0]} [options] [command ...]

where the legal options are

  -clipboard
    Asserting this option causes all output to stdout to be captured
    and placed on the system clipboard. Command-line output redirection
    is ignored.

  -filter
    Asserting this option suppresses extraneous output, making satpass
    behave more like a Unix filter.

  -initialization_file filename
    Initializes satpass from the named file. The default is
    $inifil.

  -version
    Display the version and exit. Overrides -filter if both are
    specified.

Option names can be abbreviated, as long as the abbreviation is unique.

$clipboard_unavailable
eod

$inifil || $opt{initialization_file} or warn <<eod;

Warning - Can not find home directory, and no explicit initialization
        file specified.
eod
if ($opt{initialization_file}) {
    if (-e $opt{initialization_file}) {
	$inifil = $opt{initialization_file};
	}
      else {
	warn <<eod;

Warning - File $opt{initialization_file} does not exist.
        Initializing with $inifil
eod
	}
    }

$ENV{SATPASSINI} = $inifil;

my $interrupted = 'Interrupted by user.';

$opt{clipboard} and select (IO::Clipboard->new ());

CODE_REF eq ref $Astro::satpass::Test::Hook and do {
    $fh = Astro::satpass::Test->new () or die <<eod;
Error - Failed to instantiate Astro::satpass::Test object.
eod
    select ($fh);
    no warnings qw{once};
    $SIG{__WARN__} = sub {$Astro::satpass::Test::Exception = $_[0]};
    use warnings qw{once};
    };

Getopt::Long::Configure (qw{pass_through});	# Need because of relative time format.

push @frame, {
	args => [],
	cntind => '',
	lines => [],
	parm => {},
	stdin => $fh,
	stdout => select (),
	};

$opt{version} and delete $opt{filter};

$opt{filter} or print <<eod;

satpass $VERSION - Satellite pass predictor
based on Astro::Coord::ECI @{[Astro::Coord::ECI->VERSION]}
Perl $Config{version} on $Config{osname}

Copyright 2005-2026 by Thomas R. Wyant, III.

Enter 'help' for help. See the help for terms of use.

As of release 0.057 this script is deprecated. See 'NOTES' in the help
for details.

eod
$opt{version} and exit;

########################################################################
#
#	Main program loop.
#

@ARGV and source (_memio ('<', \(join "\n", @ARGV)));

{	# Local symbol block
    my %inodes;
##    foreach my $fn ($inifn, $inifil) {	# Reverse of intended order
    foreach my $fn ($inifil) {	# Reverse of intended order
	next unless $fn && -e $fn;
	my $inode = (stat (_))[1];
	next if $inodes{$inode};
	$inodes{$inode} = $fn;
	source ($fn);
	}
    }	# End local symbol block

while (1) {

script/satpass  view on Meta::CPAN

#	with the 'core.' on the front it will be invalid, and
#	force the use of the built-in.

    (my $verb = $cmdspec) =~ s/^core\.//;
    $verb = $alias{$verb} if $alias{$verb};

#	Parse the line, pulling off output redirection as we go.

    my $redout = '';
    my @args = parse_line ('\s+', $cmdquote{$verb} || 0, $rest);
    $rest && !@args and do {
	warn <<eod;
Error - Malformed command failed to parse:
        $rest
eod
	next;
    };
    {	# Local symbol block for hacking pipe off commands
	my @pipe;
	@args = map {
	    (@pipe && !$redout) ? do {push @pipe, $_; ()} :
	    m/^([>|])/ ?
		$1 eq '|' ? do {push @pipe, $_; ()} :
		    do {$redout = $_; ()} :
	    $redout =~ m/^>+$/ ? do {$redout .= $_; ()} :
	    $_} @args;
	@pipe and $redout = join ' ', @pipe;
    }	# End local symbol block.

#	Do pseudo tilde expansion.

    eval {
	$redout =~ s/^(>+)(~.*)/ $1 . _tilde_expand ($2) /e;
	1;
    } or do {
	warn $@;
	next;
    };

#	Special-case 'exit' to drop out of the input loop.

    $verb eq 'exit' and last;

#	Arbitrarily disallow syntactically invalid commands.

    $verb =~ m/^_/ || $verb =~ m/\W/ and do {
	warn <<eod;
Error - Verb '$verb' not recognized.
eod
	next;
	};

#	Parse any command options present. Note that GetOptions is
#	configured to pass any unrecognized options because otherwise
#	our relative time format would confuse it.

    %cmdopt = ();
    {	# Begin local symbol block.
	local @ARGV = @args;
        Getopt::Long::Configure (@{$cmdconfig{$verb} ||= ['permute']});
	GetOptions (\%cmdopt, qw{clipboard debug time}, @{$cmdlgl{$verb} ||= []});
	@args = @ARGV;
	}
    $cmdopt{_redirection} = $cmdopt{clipboard} ? '-clipboard' : $redout;

#	Preserve our current output, and redirect as and if specified.

    if ($cmdopt{clipboard}) {
	$redout = '';
	my $fh = eval {IO::Clipboard->new ()};
	$@ and do {warn $@; next;};
	select ($fh) or die <<eod;
Error - Failed to redirect output to clipboard.
        $!
eod
	}
      elsif ($redout) {
	open (my $fh, $redout) or do {warn <<eod; next};
Error - Failed to open '$redout'
        $!
eod
	select ($fh) or die <<eod;
Error - Failed to redirect output to $redout.
        $!
eod
	}

#	Record start time if required.

    $frame[$#frame]{timing} = {
	command => $buffer,
	start => _time (),
    } if $cmdopt{time};

#	If our command is a macro, build an input stream from it, and
#	pass the results to the source() command. We use $cmdspec
#	because it contains the namespace 'core.' if it was specified,
#	and therefore cannot match any macro name.

    my $error;	# Status from command execution.
    if ($macro{$cmdspec}) {
	my $cmd = join "\n", @{$macro{$cmdspec}};
	source (_memio  ('<', \$cmd), @args);
	$frame[$#frame]{macro}{$cmdspec} = $macro{$verb};
	delete $macro{$cmdspec};
	}

#	Else, if there exists a subroutine named after the command,
#	call it, fielding any exceptions thrown and turning them into
#	warnings.

      elsif (my $code = __PACKAGE__->can($verb)) {
	_parse_time_reset ();	# Reset relative time base to last explicit
	local $SIG{INT} = sub {die "\n$interrupted\n"};
	eval {$code->(@args)};
	$error = $@;
	}

#	Else, complain about the unrecognized verb.

      else {
	$error = <<eod;
Error - Verb '$verb' not recognized.
eod
	}
	warn $error if $error;

#	Display timing information if desired.

    _display_timing ();

#	Unwind frame stack if needed.

script/satpass  view on Meta::CPAN

	$1 ? do {
	    my @info = eval {getpwnam ($1)} or die $@ ?
		"Error - '~user' does not work under $^O.\n" :
		"Error - No such user as '$1'.\n";
	    $info[7]
	} :
	$^O eq 'VMS' ? '/sys$login' : ($ENV{HOME} || $ENV{LOGDIR} ||
	    $ENV{USERPROFILE})%e;
    $rslt
}

#	$time = _time ()

#	The first time this is called, it attempts to load Time::HiRes.
#	If it succeeds it redefines itself to Time::HiRes::time if that
#	exists. Otherwise it redefines itself to CORE::time. Either
#	way it then transfers control to its redefined self.

sub _time () {
    eval "use Time::HiRes";
    no warnings qw{redefine};
    if (my $code = Time::HiRes->can ('time')) {
	*_time = $code;
	*_time_trim = sub {sprintf '%.3f', $_[0]};
    } else {
	*_time = \&CORE::time;
	*_time_trim = sub {$_[0]};
    }
    goto &_time;
}

{
    my @times;

    BEGIN {
	@times = map { greg_time_gm( @{ $_ } ) }
	[ 59, 59, 23, 31, 11, 2000 ],
	[ 59, 59, 11, 31, 11, 2000 ],
	;
    }

    sub _time_len {
	return max( map { length( gm_strftime( $parm{time_format}, $_ )
		) } @times );
    }
}

########################################################################

package IO::Clipboard;

use Carp;
use Config;
use Symbol;

my ($clip, $clipout, $memio);
our @ISA;

BEGIN {

$IO::Clipboard::clipboard_unavailable = '';

eval "use Scalar::Util qw{weaken}; 1"
    or $IO::Clipboard::clipboard_unavailable = <<eod;
Error - Clipboard unavailable. Unable to load Scalar::Util weaken.
eod

sub _win32 {
eval "use Win32::Clipboard" ?
    sub {(my $s = $_[0]) =~ s/\n/\r\n/mg;
	Win32::Clipboard->new ()->Set ($s)} : undef
}

sub _xclip {
no warnings;
`xclip -o`;
use warnings;
$? ? undef : sub {
    my $hdl;
    open ($hdl, '|xclip') or croak <<eod;
Error - Failed to open handle to xclip.
        $!
eod
    print $hdl $_[0];
    };
}

sub _pb {
    my $code;
    $code = eval {
	require Mac::Pasteboard;
	sub {Mac::Pasteboard::pbcopy($_[0])};
    } and return $code;
### no warnings;
system('pbcopy -help >/dev/null 2>&1');
### use warnings;
$? ? undef : sub {
    my $hdl;
    open ($hdl, '|pbcopy') or croak <<eod;
Error - Failed to open handle to pbcopy.
        $!
eod
    print $hdl $_[0];
    };
}

sub _flunk {
$IO::Clipboard::clipboard_unavailable = shift;
}

my $err = "Can not open handle to clipboard.";

$clipout = eval {$^O eq 'MSWin32' ? _win32 || _flunk (<<eod) :
Error - Clipboard unavailable. Can not load Win32::Clipboard.
eod
    $^O eq 'cygwin' ? _win32 || _xclip || _flunk (<<eod) :
Error - Clipboard unavailable. Can not load Win32::Clipboard
        and xclip has not been installed. For xclip, see
        http://freshmeat.net/projects/xclip
eod
    $^O eq 'darwin' ? _pb || _flunk (<<eod) :
Error - Clipboard unavailable. Can not load Mac::Pasteboard, and
        can not find pbcopy. The latter is supposed to come with
        Mac OS X.
eod
    $^O eq 'MacOS' ? _flunk (<<eod) :
Error - Clipboard unavailable. Mac OS 9 and below not supported.
eod
    _xclip || _flunk (<<eod)};
Error - Clipboard unavailable. Can not find xclip. For xclip,
        see http://freshmeat.net/projects/xclip
eod

$memio = $] >= 5.008 && $Config{useperlio} ?
    sub {my $fh = gensym; open ($fh, $_[0], $_[1]); $fh} :
    do {
	eval "use IO::String";
	$@ or push @ISA, 'IO::String';
        $@ ? sub {croak "$err IO::String not available"} :
	    sub {new IO::String ($_[1])};
	};

*_memio = \&$memio;
}

sub new {
return $clip if $clip;
croak $IO::Clipboard::clipboard_unavailable
    if $IO::Clipboard::clipboard_unavailable;
my $class = shift;
my $data = '';
my $clip = _memio ('>', \$data);
*$clip->{__PACKAGE__}{data} = \$data;
bless $clip, $class;
my $self = $clip;
weaken ($clip);	# So we destroy the held copy when we need to.
$self;
}

sub DESTROY {
my $self = shift;
my $data = *$self->{__PACKAGE__}{data};
$clipout->($$data);
}

########################################################################

#	Test hook.

package Astro::satpass::Test;

use Astro::Coord::ECI::Utils qw{ :ref };
use Carp;
use Config;

our @ISA;

our $noios;

unless ($] >= 5.008 && $Config{useperlio}) {
    eval "use IO::String";
    if ($@) {
	$noios = $@;
	}
    else {
	push @ISA, 'IO::String';
	}
    }

our $Hook;	# Code reference that we use to get data from.
our $Handle;	# First argument to pass to hook when called.
our $Exception;

sub new {
my $class = shift;
confess <<eod if $noios;
Programming error - You are trying to use the test hook under
        a version of Perl prior to v5.8 and you do not have
	the IO::String package available.
eod
confess <<eod unless CODE_REF eq ref $Hook;
Programming error - Should not instantiate a @{[__PACKAGE__]} object
        unless \$@{[__PACKAGE__]}::Hook has been set to a code
	reference.
eod
my $data = '';
my $hook = IO::Clipboard::_memio ('+<', \$data);
*$hook->{__PACKAGE__} = {
	data => \$data,

script/satpass  view on Meta::CPAN

and provided the user has an Internet connection and the relevant site
is functional and has the data required. This function may not be used
for commercial purposes because of restrictions Geocoder.us places on
the use of their data. You will need to install
B<Geo::Coder::OSM> to get this functionality.

* The ability to acquire the observer's height above sea level from
L<http://gisdata.usgs.gov/>, given the latitude and longitude
of the observer, and provided the user has an internet connection
and the relevant site is functional and has the data required. You will
need to install B<Geo::WebService::Elevation::USGS> to get this
functionality.

* The ability to look up star positions in the SIMBAD catalog. You will
need to install B<Astro::SIMBAD> (if using SIMBAD 3) or
B<Astro::SIMBAD::Client> (if using SIMBAD 4) to get this functionality.
The SIMBAD version is selected using the
L<simbad_version|/simbad_version> parameter.

* The ability to produce solar and lunar almanac data (rise and set,
meridian transit, and so forth).

* The ability to define macros to perform frequently-used operations.
These macros may take arguments, and make use of any L</PARAMETERS> or
environment variables. You will need to install B<IO::String> to get
this functionality unless you are running Perl 5.8 or above.

* An initialization file in the user's home directory. The file is
named satpass.ini under MacOS (meaning OS 9 - OS X is Darwin to Perl),
MSWin32 and VMS, and .satpass under any other operating system. Any
command may be placed in the initialization file. It is a good place to
set the observer's location and define any macros you want. The default
initialization file can be overridden using the SATPASSINI environment
variable or the -initialization_file command option. Internally to
satpass and any commands it spawns, environment variable SATPASSINI will
be set to the name of the initialization file actually used. See
L</ENVIRONMENT VARIABLES> for how to find out the actual initialization
file used.

=head1 COMMANDS

A number of commands are available to set operational parameters,
manage the observing list, acquire orbital elements for the observing
list, and predict satellite passes.

The command execution loop supports command continuation, which is
specified by placing a trailing '\' on the line to be continued.

It also supports a pseudo output redirection, by placing '>filename'
(for a new file) or '>>filename' (to append to an existing file)
somewhere on the command line. It is also possible to redirect the data
into a spawned command using the pipe character ('|'). Additional pipe
characters may be specified on the same command line if your operating
system supports this. Note that the redirection character B<must> be the
first character of the token; that is, 'pass >file.txt' or 'pass |less',
but not 'pass>file.txt' or 'pass|less'. See the L</SYNOPSIS> for
examples.

In addition, all commands support the following options:

-clipboard places the output of the command on the clipboard. This
will be discussed more below.

-debug is accepted but not supported - that is, the author makes
no claims of what will happen if you assert it, and reserves the
right to change this behavior without warning. It is really a
development aid.

-time causes the elapsed time of the command in seconds to be
displayed. This is another development aid.

Individual commands may have options specific to them. Option names
may be abbreviated, provided the abbreviation is unique among all
options valid for that command. They may appear anywhere in the
command line unless otherwise documented with the specific command
('system' being the only exception at the moment).

If the -clipboard option is asserted, output to standard out will
be placed on the clipboard. This output will not appear on the
clipboard until the command completes.

The clipboard functionality requires the availability of the
Win32::Clipboard module under MSWin32 (standard with ActivePerl), the
Mac::Pasteboard module or the pbcopy command under darwin (and any Mac
OS X I know of comes with pbcopy and pbpaste), or the xclip command
(available from L<http://freshmeat.sourceforge.net/projects/xclip>)
under any other operating system.

The clipboard functionality is implemented as a singleton object,
so that if you redirect output away from the clipboard and then
back to it, both sets of clipboard data are considered to be the
same data stream, and both end up on the clipboard, without the
intervening data.

The command loop also supports rudimentary interpolation of arguments
and other values into commands. The "magic" character is a dollar sign,
which may be followed by the name of what is to be substituted. A
number represents the corresponding macro or source argument (numbered
from 1), and anything else represents the value of the named parameter
(if it exists) or environment variable (if not). The name may be
optionally enclosed in curly brackets.

If the name of the thing substituted is enclosed in curly brackets, it
may be optionally followed by other specifications, as follows:

${arg:-default} substitutes in the default if the argument is undef or
the empty string. If the argument is 0, the default will B<not> be
substituted in.

${arg:=default} not only supplies the default, but sets the value of
the argument to the specified default. Unlike bash, this works for
B<any> argument.

${arg:?message} causes the given message to be displayed if the
argument was not supplied, and the command not to be processed. If this
happens when expanding a macro or executing a source file, the entire
macro or file is abandoned.

${arg:+substitute} causes the substitute value to be used provided the
argument is defined. If the argument is not defined, you get an empty
string.

${arg:default} is the same as ${arg:-default}, but the first character
of the default B<must> be alphanumeric.

Interpolation is not affected by quotes. If you want a literal dollar
sign in the expansion of your macro, double the dollar signs in the
definition. It is probably a good idea to put quotes around
an interpolation in case the interpolated value contains spaces.

For example:

 macro ephemeris 'almanac "$1"'

sets up "ephemeris" as a synonym for the 'almanac' command. The
forward-looking user might want to set up

 macro ephemeris 'almanac "${1:tomorrow midnight}"'

which is like the previous example except it defaults to
'tomorrow midnight', where the 'almanac' command defaults to
'today midnight'.

As a slightly less trivial example,

 macro ephemeris 'almanac "${1:=tomorrow midnight}"' 'quarters "$1"'

which causes the quarters command to see 'tomorrow midnight' if no
arguments were given when the macro is expanded.

The following commands are available:

script/satpass  view on Meta::CPAN

fatal.

See the L<Astro::Coord::ECI::TLE|Astro::Coord::ECI::TLE> documentation
for information on how this list is populated initially.  If you have
installed Astro::SpaceTrack, you can update the status using the 'st
iridium_status' command, or you can update it using the 'add', 'clear',
and 'drop' subcommands, which are discussed in more detail below.

The 'status' command also takes the following subcommands:

add - adds the given body to the status list. The arguments are NORAD
ID, satellite type ('iridium' is the only valid type at the moment),
status ('+' for in-service, 'S' for spare, '-' for tumbling or otherwise
unable to flare), name (e.g.  'Iridium 12'), and a comment, with the
status defaulting to '+', and name and comment to ''. For example:

 satpass> status add 12345 iridium S 'Bogus body' TRW

The 'add' command can also be used to change the status of an existing
body, with the new entry replacing the old.

drop - removes the given body from the status list. You will get a
message if the body does not exist. For example, to remove the
previously-added bogus body,

 satpass> status drop 12345

show - is equivalent to a bare status command, and displays all known
statuses. However, you can also specify the bodies to display as either
NORAD IDs or names or a mixture of both. Names will be taken as regular
expressions. For example:

 satpass> status show 36 97

to display the status of Iridium 36 and 97.

=item store

 satpass> store filename

This command is one half of the interface to the Storable module.
It uses the nstore() subroutine to write the observing list to
the given file.

=item system

 satpass> system command

This command passes its arguments to the system as a command. The
results are displayed unless redirected.

Technically, what happens is that if the current output is a tty,
the command is executed using the core system command; otherwise
its output is captured with backticks and printed.

If the command is omitted, the value of environment variable SHELL
is used as the command, with the intent of dropping you into the
given shell. If environment variable SHELL is not defined and you
are running under MSWin32, value 'cmd' is used as the command.

The -clipboard qualifier B<must> come immediately after the verb
'system', and before the name of the command you are actually
issuing if any. This restriction is to prevent legal qualifiers
from being stripped from the command. For example:

 satpass> system -c ls

Issues the 'ls' command, and captures the output on the clipboard.
That is to say the satpass script handles the -c. But

 satpass> system ls -c

displays the status change time of the file, with output going to
standard out. That is to say the ls command handles the -c.

=item times

 satpass> times time

This command displays the universal, dynamical, local standard,
local mean, and local time for the given input time.

The time defaults to the current time.

=item tle

 satpass> tle

This command displays the original two- or three- line element data
which was used to build the observation list.

In addition to the global options, the following options are legal for
the tle command:

-choose chooses bodies from the observing list. It works the same way
as the L<choose|/choose> command, but does not alter the observing
list. You can specify multiple bodies by specifying -choose multiple
times, or by separating your choices with commas. If -choose is not
specified, the whole observing list is used.

The C<-verbose> qualifier causes the data to be displayed verbosely,
one item per line, labeled and with units if applicable.

=item validate start_time end_time

This command validates the observing list over the given time range,
dropping any TLEs that do not validate.  See the L</SPECIFYING TIMES>
topic below for how to specify times.

In addition to the global options, the following options are legal for
the validate command:

-quiet suppresses any errors generated by running the orbital model.
These are typically from obsolete data, and/or decayed satellites.

The defaults are 'today noon' and seven days after the start time
respectively.

=back

=head1 PARAMETERS

This script has a number of parameters to configure its operation. In
general:

Strings must be quoted if they contain blanks. Either kind of quotes
will work, but back ticks will not.

script/satpass  view on Meta::CPAN

The internal routine is rather permissive about punctuation: any
non-digit character is accepted, and multiple whitespace characters are
accepted between date and time, and between time and zone. Years can be
two- or four-digit, with two-digit years representing years between 1970
and 2069, inclusive. Any other date or time field can be shortened if it
has trailing punctuation or is the last field specified before the zone.

In addition, the internal routine accepts the strings 'yesterday',
'today', and 'tomorrow' in lieu of a date. If time is not specified,
these represent midnight.

So, using the internal parser the following are valid:

 today     'today 12:00'  '2009/2/1 6:00Z' (i.e. February 1)
 tomorrow  yesterday6:00

As a refresher, ISO-8601 dates are numeric and specified as year, month,
and day. If all fields are full-width (4 digits for years, 2 for
everything else) no punctuation at all is needed, other than in an
optional zone specification.

=head2 Relative time

A relative time is specified by '+' or '-' and an integer number of
days. The number of days must immediately follow the sign. Optionally,
a number of hours, minutes, and seconds may be specified by placing
whitespace after the day number, followed by hours:minutes:seconds. If
you choose not to specify seconds, omit the trailing colon as well. The
same applies if you choose not to specify minutes. For example:

+7 specifies 7 days after the last-specified time.

'+7 12' specifies 7 days and 12 hours after the last-specified time.

If a relative time is specified as the first time argument of a command,
it is relative to the most-recently-specified absolute time, even if
that absolute time was specified by default. Relative times in subsequent
arguments to the same command are relative to the previously-specified
time, whether absolute or relative. For example:

 almanac '' +5

establishes the most-recently-specified time as 'today midnight', and does
an almanac for 5 days from that time. If the next command is

 almanac +5 +3

this produces almanac output for three days, starting 5 days after
'today midnight'.

=head1 INVOCATION

Assuming this script is installed as an executable, you should be able
to run it just by specifying its name. Under VMS, the DCL$PATH logical
name must include the directory into which the script was installed.

The only command qualifiers are

=over

=item -clipboard

which causes all output to go to the clipboard. Use of this qualifier
requires module Win32::Clipboard under MSWin32 (standard with
ActivePerl), the Mac::Pasteboard module or the 'pbcopy' command under
Darwin (the latter standard with Mac OS X), or the xclip command
(available from L<http://freshmeat.sourceforge.net/projects/xclip>)
under any other operating system. This script will warn and abort the
command using this option if the requisites are not available.

=item -filter

which suppresses extraneous output to make satpass behave more like a
Unix filter. The only thing suppressed at the moment is the banner text.

=item -initialization_file filename

which specifies an initialization file to use in place of the default.

=item -version

which causes the banner text to be displayed and the script to exit.
This option overrides -filter if both are specified.

=back

These qualifiers can be abbreviated, as long as the abbreviation is
unique.

It is also possible to pass commands on the command line, or to pipe or
redirect them in. The execution order is

 1. The initialization file;
 2. Commands on the command line;
 3. Commands from standard input.

For example, assuming the initialization file defines a macro named
'usual' to load the usual observing list, you could do:

 $ satpass usual 'pass "today noon" +1' exit

to display passes for the next day. Obviously you may need to play
games with your shell's quoting rules. In the above example,
MSWin32 and VMS users would be advised to interchange the single
and double quotes.

Should you wish to execute the above from a file, each command needs
to go on its own line, thus:

  usual
  pass "today noon" +1
  exit

and the file is then invoked using either

  $ satpass <commands

(assuming 'commands' is the name of the file), or, under the same
naming assumption,

  $ satpass 'source commands'

or (under some flavor of Unix)

  $ cat commands | satpass

or even

  $ satpass `cat commands`

=head1 ENVIRONMENT VARIABLES

SATPASSINI can be used to specify an initialization file to use in lieu
of the default. This can still be overridden by the
-initialization_file command option. To see the current setting,

 satpass> echo $SATPASSINI

which reports the name of the file actually used to initialize.

=head1 ACKNOWLEDGMENTS

L<Astro::Coord::ECI|Astro::Coord::ECI> acknowledges those without whom
this code would not exist. But the script has its own issues, and I
would like to acknowledge here those who made this script better:

Imacat of Tavern IMACAT in Taiwan, for helping me to work out a satpass
script testing problem.

=head1 BUGS

Support is by the author. Please file bug reports at
L<https://rt.cpan.org/Public/Dist/Display.html?Name=Astro-satpass>,
L<https://github.com/trwyant/perl-Astro-Coord-ECI/issues>, or in
electronic mail to the author.

The VMS- and MSWin32-specific code to find the initialization file and
do tilde expansion is untested, since I do not currently have access to
those systems.

As of 0.003, clipboard functionality is provided by this code, not by
the Clipboard module, making clipboard bugs mine also.

=head1 AUTHOR

Thomas R. Wyant, III (F<harryfmudd at comcast dot net>)

=head1 COPYRIGHT AND LICENSE

Copyright (C) 2005-2026 by Thomas R. Wyant, III

This program is free software; you can redistribute it and/or modify it
under the same terms as Perl 5.10.0. For more details, see the full text
of the licenses in the files F<LICENSE-Artistic> and F<LICENSE-GPL>.

This program is distributed in the hope that it will be useful, but
without any warranty; without even the implied warranty of
merchantability or fitness for a particular purpose.

TIGER/LineE<reg> is a registered trademark of the U.S. Census Bureau.

=cut

# ex: set textwidth=72 :



( run in 0.795 second using v1.01-cache-2.11-cpan-2398b32b56e )