summaryrefslogtreecommitdiffstats
path: root/xcfview.in
blob: 38abcfb32ba96c81ae5e4479d35ca97d8451ba54 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
#! /usr/bin/perl
#
#  xcfview: a wrapper script that uses xcftools and an external viewer
#  to display XCF images. The external viewer is found through the
#  mailcap(5) database (q.v.).
#
#  Written by Henning Makholm <henning@makholm.net>
#  Derived from the run-mailcap script by Brian White <bcwhite@pobox.com>
#
#  This script has been placed in the public domain (by both authors)
#
#  We cannot use run-mailcap as-is because we can supply the flattened
#  image either as PNG and PPM, and we need to find the highest-ranked
#  viewer that can handle _one_ of these two. If everything else is equal
#  we try to prefer a PNG viewer such that transparency is handled properly.
#

use strict ;
use warnings ;

my $debug=0;
my $quotedsemi = "\001" ;
my $quotedprct = "\002" ;

sub ReadMailcap {
	my($file) = @_;
	my $line = "";

	return unless -r $file;

	print STDERR " - Reading mailcap file \"$file\"...\n" if $debug;
	open(MAILCAP,"<$file") || die "Error: could not read \"$file\" -- $!\n";
        my @mailcap ;
        
	while (<MAILCAP>) {
		chomp;
		s/^\s+// if $line;
		$line .= $_;
		next unless $line;
		if ($line =~ m/^\s*\#/) {
			$line = "";
			next;
		}
		if ($line =~ m/\\$/) {
			$line =~ s/\\$//;
		} else {
			$line =~ s/\\;/$quotedsemi/go;
			$line =~ s/\\%/$quotedprct/go;
			push @mailcap,$line;
			$line = "";
		}
	}
	close MAILCAP;

        return @mailcap ;
}

sub TempFile {
	my($match) = @_;
	my($cmd,$head,$tail,$tmpfile);

        ($head,$tail) = split(/%s/,$1,2)
            if ($match =~ m/nametemplate=(.*?)\s*($|;)/);

	$cmd  = "tempfile --mode=600";
	$cmd .= " --prefix $head" if $head;
	$cmd .= " --suffix $tail" if $tail;

	$tmpfile = `$cmd`;
	chomp($tmpfile);

	return $tmpfile;
}

my ($useline,$usecomm,$useprogram,$usetype,@converter) ;
foreach my $mailcap ( $ENV{MAILCAPS} ? split(/:/,$ENV{MAILCAPS}) :
                      ( "$ENV{HOME}/.mailcap",
                        qw( /etc/mailcap
                            /usr/local/etc/mailcap
                            /usr/share/etc/mailcap
                            /usr/etc/mailcap
                            ) ) ) {
    foreach ( ReadMailcap($mailcap) ) {
        my ($type,$comm,$program,$rest)
            = m"^image/(png|x-portable-pixmap)\s*;\s*((\S*).*?)\s*($|;.*)"
            or next ;
        print STDERR " - checking $mailcap entry \"$_\"\n" if $debug;
        next if $rest =~ /;\s*needsterminal\s*($|;)/ ;
        next if $rest =~ /;\s*copiousoutput\s*($|;)/ ;
        if( $rest =~ m/;\s*test=(.*?)\s*($|;)/ ) {
            my $test;
            print STDERR " - running test: $1 " if $debug;
            $test   = system "$1 >/dev/null 2>&1";
            $test >>= 8;
            print STDERR " (result=$test=",($test!=0?"false":"true"),")\n"
                if $debug;
            next if $test ;
        }
        # If we get down here, we have a possible hit.
        if( $type ne 'png' ) {
            # Save for later; if there is a PNG definition for the same
            # command, we will prefer PNG
            ($useline,$usecomm,$useprogram,$usetype,@converter)
                = ($rest,$comm,$program,$type,"xcf2pnm","-c","'-#'")
                unless @converter ;
            next ;
        } else {
            # use this definition _unless_ we have already seen and saved
            # a definition for a _different_ program (which must have been PPM)
            ($useline,$usecomm,$useprogram,$usetype,@converter)
                = ($rest,$comm,$program,$type,"xcf2png")
                unless @converter && $comm eq $useprogram ;
            last ;
        }
    }
    last if @converter ;
}

unless( @converter ) {
    print STDERR "$0: No appropriate way to display PPM or PNG images in mailcap\n" ;
    exit 1 ;
}

sub finishcomm() {
    $usecomm =~ s!([^%])%t!$1$usetype!g;
    $usecomm =~ s!%{(.*?)}!$_="'$ENV{$1}'";s/\`//g;$_!ge;
    $usecomm =~ s!\\(.)!$1!g;
    $usecomm =~ s!\'\'!\'!g;
    $usecomm =~ s!$quotedsemi!;!go;
    $usecomm =~ s!$quotedprct!%!go;
}

# quote arguments for converter
for( @ARGV ) {
    next if m{^[-a-z0-9,.:/@%^+=_]+$}i ;
    s/'/\\'/ ;
    $_ = "'$_'" ;
}

if( $usecomm =~ /[^%]%s/ ) {
    my $tempfile = TempFile($useline);
    $usecomm =~ s/([^%])%s/$1$tempfile/g ;
    finishcomm() ;
    my $retcode = 0 ;
    for my $comm ( join(" ",@converter,"-o",$tempfile,@ARGV),
                   $usecomm ) {
        print STDERR " - executing: $comm\n" if $debug ;
        my $res = system $comm;
        $res = int($res/256);
        if ($res != 0) {
            print STDERR "Warning: program returned non-zero exit code \#$res\n";
            $retcode = $res;
            last ;
        }
    }
    unlink $tempfile ;
    exit $retcode ;
} else {
    finishcomm() ;
    exec( join(@converter," ",@ARGV) . " | " . $usecomm )
        or print STDERR "Couldn't exec pipeline: $!\n" ;
    exit 1 ;
}