Current File : //kunden/bin/paper |
#!/usr/bin/perl
# -*- perl -*-
use 5.10.1;
use strict;
use warnings;
use locale;
# Relocatable header (see after for copyright)
# The functions in this file provide support for relocatability of
# Perl scripts. They should be included near the beginning of each
# Perl script in a relocatable program, by adding @relocatable_pl@
# and causing the script to be expanded with AC_CONFIG_FILES. A
# small amount of additional code must be added and adapted to the
# package by hand; see doc/relocatable-maint.texi (in Gnulib) for
# details.
#
# This code is based on relocatable.sh.in, and design changes (and
# bugs) should probably be cross-checked with it.
#
# Copyright (C) 2013, 2015-2022 Free Software Foundation, Inc.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# 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. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
#
use Config;
use File::Basename;
use File::Spec::Functions;
use Cwd 'realpath';
# Support for relocatability.
sub find_curr_installdir {
# Determine curr_installdir, even taking into account symlinks.
my $curr_executable = $0;
my $basename = basename($0);
if ($curr_executable eq $basename) {
LOOP: for my $dir (split /$Config{path_sep}/, $ENV{PATH}) {
$dir = "." unless $dir;
for my $ext ('') {
my $filename = catfile($dir, "$curr_executable$ext");
if (-f $filename) {
$curr_executable = $filename;
last LOOP;
}
}
}
}
# Resolve symlinks and canonicalize.
return realpath(dirname($curr_executable));
}
sub find_prefixes {
# Compute the original/current installation prefixes by stripping the
# trailing directories off the original/current installation directories.
my ($orig_installprefix, $curr_installprefix) = @_;
my $orig_last = basename($orig_installprefix);
my $curr_last = basename($curr_installprefix);
if ($orig_last && $curr_last && $orig_last eq $curr_last) {
$orig_installprefix = dirname($orig_installprefix);
$curr_installprefix = dirname($curr_installprefix);
}
return $orig_installprefix, $curr_installprefix;
}
if ("no" eq "yes") {
my $exec_prefix = "/usr";
my $orig_installdir = "/usr/bin"; # see Makefile.am's *_SCRIPTS variables
my ($orig_installprefix, $curr_installprefix) = find_prefixes($orig_installdir, find_curr_installdir());
sub relocate { # the subroutine is defined whether or not the enclosing block is executed
my ($dir) = @_;
if ("no" eq "yes") {
$dir =~ s%^$orig_installprefix/%$curr_installprefix/%;
$dir =~ s,/$,,;
}
return $dir;
}
}
# Relocate the directory variables that we use.
my $libexecdir = &relocate("/usr/libexec");
my $sysconfdir = &relocate("/etc");
# End of relocatable header; "real" Perl starts here.
use Scalar::Util qw(looks_like_number);
use File::Basename;
use File::Spec::Functions;
use Getopt::Long;
my $program_name = basename($0);
$program_name =~ s/\Q.pl\E$//;
my $version_banner = <<END;
$program_name 2.3
Copyright (c) 2013-2020 Reuben Thomas <rrt\@sc3d.org>.
Released under the GPL version 3, or (at your option) any later version.
END
sub Die {
say STDERR "$program_name: $_[0]";
exit(1);
}
my %units = (
"pt" => 1,
"mm" => 72 * .1 / 2.54,
"in" => 72,
);
my $unit_err = "bad unit (valid units: " . join(", ", keys %units) . ")";
sub usage {
my ($exit_code) = @_;
print STDERR <<END;
Usage: $program_name [OPTION...] [PAPER...|--all]
Print paper size information.
--all print information about all known paper sizes
--name print paper names (by default, the name is not
printed when only one paper argument is given)
--size print paper sizes (width followed by height)
--unit=UNIT print dimensions in the given unit
[default: PostScript points]
--help display this help and exit
--version display version information and exit
END
exit $exit_code;
}
# Parse command-line options
my ($opt_all, $opt_name, $opt_size, $opt_help, $opt_version);
my $unit = "pt";
my $opts = GetOptions(
"all" => \$opt_all,
"name" => \$opt_name,
"size" => \$opt_size,
"unit=s" => \$unit,
"help" => \$opt_help,
"version" => \$opt_version,
) or usage(1);
if ($opt_version) {
print STDERR $version_banner;
exit 0;
}
usage(0) if $opt_help;
my $dim = $units{$unit} or Die($unit_err);
usage(1) if $opt_all && $#ARGV >= 0;
# Initialise papers list
sub readspecs {
my ($file) = @_;
my @papers;
return unless open(PAPERSPECS, $file);
while (<PAPERSPECS>) {
chomp $_;
my ($name, $w, $h, $unit) = split /,/;
$name =~ s/ //;
local *local_die = sub { Die("$_[0] in line $. of $file"); };
local_die("missing field") if !defined($name) || !defined($w) || !defined($h) || !defined($unit);
local_die("bad width") unless looks_like_number($w);
local_die("bad height") unless looks_like_number($h);
my $dim = $units{$unit};
local_die($unit_err) unless $dim;
push @papers, {name => $name, width => $w * $dim, height => $h * $dim};
}
close(PAPERSPECS);
return @papers;
}
my (@papers, @user_papers, @system_papers, $default_paper);
my $xdg_config_home = $ENV{XDG_CONFIG_HOME};
unless ($xdg_config_home) {
my $home = $ENV{HOME};
$xdg_config_home = catfile($home, ".config") if $home;
}
@user_papers = readspecs(catfile($xdg_config_home, "paperspecs"));
@system_papers = readspecs(catfile($sysconfdir, "paperspecs"));
$default_paper = $system_papers[0] || $user_papers[0] || Die("no paper sizes configured");
push @papers, @user_papers, @system_papers;
# Get paper type from the locale
sub mm_to_pt { int(($_[0] * 72 / 2.54 / 10) + 0.5); }
sub trim {
my ($s) = @_;
$s =~ s/^\s+|\s+$//g;
return $s;
}
sub papernamefile {
my ($file) = @_;
open(PAPERSIZE, $file) or return;
my $output = do {local $/, <PAPERSIZE>} or return;
return trim($output);
}
sub localepapername {
my $localepaper = catfile($libexecdir, "localepaper");
my $dims = `$localepaper` or return;
chomp $dims;
return if !defined($dims);
my ($w, $h) = split /\s/, $dims;
return if !looks_like_number($w) || !looks_like_number($h);
($w, $h) = map { mm_to_pt($_) } $w, $h;
foreach my $p (@papers) {
return $p->{name} if int($p->{width} + 0.5) == $w && int($p->{height} + 0.5) == $h;
}
}
# Work out user's current paper size
sub currentpaper {
return $ENV{PAPERSIZE} ||
papernamefile(catfile($xdg_config_home, "papersize")) ||
localepapername() ||
papernamefile(catfile($sysconfdir, "papersize")) ||
$default_paper->{name};
}
sub paperinfo {
my ($paper) = @_;
foreach my $p (@papers) {
return $p if $p->{name} =~ /^$paper$/i;
}
}
# Output requested information
map { push @ARGV, $_->{name} } @papers if $opt_all;
$opt_name = 1 if $#ARGV > 0;
if ($#ARGV == -1) {
my $paper = currentpaper() or Die("no default paper size is set");
push @ARGV, $paper;
}
foreach my $name (@ARGV) {
my $p = paperinfo($name) or Die("unknown paper `$name'");
my @out;
push @out, $p->{name} if $opt_name || $opt_all || !$opt_size;
push @out, $p->{width} / $dim, $p->{height} / $dim if $opt_size;
say join(' ', @out);
}