summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorgregor herrmann <gregoa@debian.org>2020-10-31 01:37:35 +0100
committergregor herrmann <gregoa@debian.org>2020-10-31 01:37:35 +0100
commit931d852d404398a0b3c8aacc16f1b012b5ac8461 (patch)
tree671bcef27936aabe70c1b55307d1bd8a0c2e4ac7
parent1c430a92837eb5ba044910d01203eef67b15138c (diff)
parente81ee0e34865a80770d1745d73e81afca486ede2 (diff)
New upstream version 0.30
-rw-r--r--Changes37
-rw-r--r--META.json12
-rw-r--r--META.yml8
-rw-r--r--Makefile.PL4
-rw-r--r--README.md6
-rw-r--r--lib/File/MimeInfo.pm461
-rw-r--r--lib/File/MimeInfo/Applications.pm307
-rw-r--r--lib/File/MimeInfo/Magic.pm376
-rw-r--r--lib/File/MimeInfo/Rox.pm101
-rwxr-xr-xmimeopen314
-rwxr-xr-xmimetype300
-rw-r--r--t/000-report-versions-tiny.t5
-rw-r--r--t/00_use_ok.t6
-rw-r--r--t/01_normal.t86
-rw-r--r--t/02_magic.t12
-rw-r--r--t/03_rox.t12
-rw-r--r--t/04_IO_objects.t28
-rw-r--r--t/05_more.t83
-rw-r--r--t/06_pod_ok.t2
-rw-r--r--t/10filehandle.t4
-rw-r--r--t/11mimeinfo.t15
21 files changed, 1148 insertions, 1031 deletions
diff --git a/Changes b/Changes
index f413bc1..dbc1ca8 100644
--- a/Changes
+++ b/Changes
@@ -2,13 +2,26 @@ Revision history for Perl extension File::MimeInfo.
Versions up to 0.15 by Jaap Karssenberg <pardus@cpan.org>
Versions starting 0.16 by Michiel Beijen <michiel.beijen@gmail.com>
+0.30 2020-10-26
+ - Added function File::MimeInfo::has_mimeinfo_database() to test if
+ mimeinfo database is found
+ - mimetype and mimeopen now exit with an error code if no mimeinfo database
+ is found
+ - Added explicit dependency on Encode::Locale
+ - Properly decode parameters for `mimeopen` and `mimetype`.
+ Patch provided by Nikos Skalkotos
+ - Fix for undefined defaults (fixes #36).
+ Reported & fix provided by Martin Vassor
+ - Improved installation instructions, specifically on macOS, by
+ Oleg Kostyuk & Michiel Beijen
+
0.29 2018-08-05
- Stable release to CPAN.
0.28_03 2017-01-22
- `mimeinfo --stdin` did not work. Reported by Marius Gavrilescu,
- Debian bug https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=784545
- Added minimal tests for `mimeinfo`.
+ Debian bug https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=784545
+ Added minimal tests for `mimeinfo`.
0.28_02 2016-12-17
- Improved handling of Path::Tiny objects in default method.
@@ -16,21 +29,21 @@ Versions starting 0.16 by Michiel Beijen <michiel.beijen@gmail.com>
0.28_01 2016-11-29
- Spelling fix courtesy gregor herrmann, Debian Perl group (fixes #25)
- Added t/000-report-versions-tiny.t to find out issue with Path::Tiny file
- handles.
+ handles.
0.28 2016-11-27
- Follow the current mime-apps-spec (fixes #8, #20)
- The current version of the mime-apps spec locates the per-user defaults
- file in `$XDG_CONFIG_HOME/mimeapps.list`. Use that location, and fall
- back to the per-system and distribution defaults as specified, with the
- previous legacy defaults file as a final fallback.
- Fix by Patrick Burroughs (Celti)
+ The current version of the mime-apps spec locates the per-user defaults
+ file in `$XDG_CONFIG_HOME/mimeapps.list`. Use that location, and fall
+ back to the per-system and distribution defaults as specified, with the
+ previous legacy defaults file as a final fallback.
+ Fix by Patrick Burroughs (Celti)
- POD clarifications by Nitish Bezzala
0.27 2015-02-23
- Allow to use mimeinfo on a Path::Tiny object. Reported by Smylers.
- Misspelled NoDisplay attribute in .desktop file.
- Fix by Bernhard Rosenkraenzer (berolinux)
+ Fix by Bernhard Rosenkraenzer (berolinux)
- Fix typos in README by Sean Smith (ncstang) as part of CPAN Pull Request
Challenge February 2015.
@@ -47,8 +60,8 @@ Versions starting 0.16 by Michiel Beijen <michiel.beijen@gmail.com>
0.23 2014-04-02
- Fixed opening of files with '+' in mime type using
- File::MimeInfo::Applications.
- Debian bug 690334, brian m. carlson.
+ File::MimeInfo::Applications.
+ Debian bug 690334, brian m. carlson.
0.22 2014-02-27
- Fixed Double-close on a filehandle issue (RT 93221) - Christian Ludwig.
@@ -143,7 +156,7 @@ Versions starting 0.16 by Michiel Beijen <michiel.beijen@gmail.com>
0.9 2003-12-05
- Fixed magic() and default() to work on IO::something objects
- Added a "no warnings" in the default routine to suppress warnings when
- input is latin2 (thus neither ascii or utf8). Not sure whether this
+ input is latin2 (thus neither ascii or utf8). Not sure whether this
really fixes the problem but it at least ignores it.
The problem was reported by Daniel Raska.
diff --git a/META.json b/META.json
index 492cffe..bb73959 100644
--- a/META.json
+++ b/META.json
@@ -4,13 +4,13 @@
"Jaap Karssenberg <pardus@cpan.org>"
],
"dynamic_config" : 1,
- "generated_by" : "ExtUtils::MakeMaker version 7.18, CPAN::Meta::Converter version 2.150010",
+ "generated_by" : "ExtUtils::MakeMaker version 7.44, CPAN::Meta::Converter version 2.150010",
"license" : [
"perl_5"
],
"meta-spec" : {
"url" : "http://search.cpan.org/perldoc?CPAN::Meta::Spec",
- "version" : "2"
+ "version" : 2
},
"name" : "File-MimeInfo",
"no_index" : {
@@ -23,6 +23,7 @@
"build" : {
"requires" : {
"Carp" : "0",
+ "Encode::Locale" : "0",
"Exporter" : "0",
"Fcntl" : "0",
"File::BaseDir" : "0.03",
@@ -55,15 +56,18 @@
"url" : "https://github.com/mbeijen/File-MimeInfo"
}
},
- "version" : "0.29",
+ "version" : "0.30",
"x_contributors" : [
"Bernhard Rosenkränzer <bero@lindev.ch>",
"Christian Ludwig <chrissicool@gmail.com>",
"David Steinbrunner <dsteinbrunner@pobox.com>",
"Jitka Plesnikova <jplesnik@redhat.com>",
"Jonathan Dowland <jmtd@debian.org>",
+ "Martin Vassor <martin.vassor@alumni.epfl.ch>",
"Michiel Beijen <michiel.beijen@gmail.com>",
+ "Nikos Skalkotos <skalkoto@grnet.gr>",
"Nitish Bezzala <nbezzala@yahoo.com>",
+ "Oleg Kostyuk <cub.uanic@gmail.com>",
"Patrick Burroughs (Celti) <celti@celti.name>",
"Rudolf Leermakers <rudolf@hatsuseno.org>",
"Sean Smith <ssmith@ncsgraphics.com>",
@@ -71,5 +75,5 @@
"brian m. carlson <sandals@crustytoothpaste.net>",
"gregor herrmann <gregoa@debian.org>"
],
- "x_serialization_backend" : "JSON::PP version 2.27300"
+ "x_serialization_backend" : "JSON::PP version 4.04"
}
diff --git a/META.yml b/META.yml
index 6332f27..51b00fc 100644
--- a/META.yml
+++ b/META.yml
@@ -4,6 +4,7 @@ author:
- 'Jaap Karssenberg <pardus@cpan.org>'
build_requires:
Carp: '0'
+ Encode::Locale: '0'
Exporter: '0'
Fcntl: '0'
File::BaseDir: '0.03'
@@ -13,7 +14,7 @@ build_requires:
configure_requires:
ExtUtils::MakeMaker: '6.30'
dynamic_config: 1
-generated_by: 'ExtUtils::MakeMaker version 7.18, CPAN::Meta::Converter version 2.150010'
+generated_by: 'ExtUtils::MakeMaker version 7.44, CPAN::Meta::Converter version 2.150010'
license: perl
meta-spec:
url: http://module-build.sourceforge.net/META-spec-v1.4.html
@@ -28,15 +29,18 @@ requires:
resources:
bugtracker: https://github.com/mbeijen/File-MimeInfo/issues
repository: https://github.com/mbeijen/File-MimeInfo
-version: '0.29'
+version: '0.30'
x_contributors:
- 'Bernhard Rosenkränzer <bero@lindev.ch>'
- 'Christian Ludwig <chrissicool@gmail.com>'
- 'David Steinbrunner <dsteinbrunner@pobox.com>'
- 'Jitka Plesnikova <jplesnik@redhat.com>'
- 'Jonathan Dowland <jmtd@debian.org>'
+ - 'Martin Vassor <martin.vassor@alumni.epfl.ch>'
- 'Michiel Beijen <michiel.beijen@gmail.com>'
+ - 'Nikos Skalkotos <skalkoto@grnet.gr>'
- 'Nitish Bezzala <nbezzala@yahoo.com>'
+ - 'Oleg Kostyuk <cub.uanic@gmail.com>'
- 'Patrick Burroughs (Celti) <celti@celti.name>'
- 'Rudolf Leermakers <rudolf@hatsuseno.org>'
- 'Sean Smith <ssmith@ncsgraphics.com>'
diff --git a/Makefile.PL b/Makefile.PL
index 6ac80e9..511935b 100644
--- a/Makefile.PL
+++ b/Makefile.PL
@@ -16,6 +16,7 @@ WriteMakefile (
'BUILD_REQUIRES' => {
'Carp' => 0,
'Exporter' => 0,
+ 'Encode::Locale' => 0,
'Fcntl' => 0,
'Pod::Usage' => 0,
'File::BaseDir' => '0.03',
@@ -50,8 +51,11 @@ WriteMakefile (
'David Steinbrunner <dsteinbrunner@pobox.com>',
'Jitka Plesnikova <jplesnik@redhat.com>',
'Jonathan Dowland <jmtd@debian.org>',
+ 'Martin Vassor <martin.vassor@alumni.epfl.ch>',
'Michiel Beijen <michiel.beijen@gmail.com>',
+ 'Nikos Skalkotos <skalkoto@grnet.gr>',
'Nitish Bezzala <nbezzala@yahoo.com>',
+ 'Oleg Kostyuk <cub.uanic@gmail.com>',
'Patrick Burroughs (Celti) <celti@celti.name>',
'Rudolf Leermakers <rudolf@hatsuseno.org>',
'Sean Smith <ssmith@ncsgraphics.com>',
diff --git a/README.md b/README.md
index 53a3441..b4a26cf 100644
--- a/README.md
+++ b/README.md
@@ -6,6 +6,12 @@ trying to implement the freedesktop specification for using the shared
mime-info database. The package comes with a script called `mimetype`
that can be used as a `file(1)` work-alike.
+Because this module uses the FreeDesktop MIME database, it's most
+suited for use in perl scripts that run on a desktop OS; in fact,
+this module is typically pre-installed on Debian and Ubuntu OSes
+so you can use its command line script `mimeopen` to open files in
+the GUI just like you can use `open` on macOS.
+
## INSTALLATION
To install this module type the following:
diff --git a/lib/File/MimeInfo.pm b/lib/File/MimeInfo.pm
index 0f0dd86..23b149a 100644
--- a/lib/File/MimeInfo.pm
+++ b/lib/File/MimeInfo.pm
@@ -1,6 +1,7 @@
package File::MimeInfo;
use strict;
+use warnings;
use Carp;
use Fcntl 'SEEK_SET';
use File::Spec;
@@ -10,10 +11,10 @@ require Exporter;
our @ISA = qw(Exporter);
our @EXPORT = qw(mimetype);
our @EXPORT_OK = qw(extensions describe globs inodetype mimetype_canon mimetype_isa);
-our $VERSION = '0.29';
+our $VERSION = '0.30';
our $DEBUG;
-our ($_hashed, $_hashed_aliases, $_hashed_subclasses);
+our ($_hashed, $_hashed_aliases, $_hashed_subclasses, $_has_mimeinfo_database);
our (@globs, %literal, %extension, %mime2ext, %aliases, %subclasses);
our ($LANG, @DIRS);
# @globs = [ [ 'glob', qr//, $mime_string ], ... ]
@@ -28,263 +29,270 @@ our ($LANG, @DIRS);
sub new { bless \$VERSION, shift } # what else is there to bless ?
sub mimetype {
- my $file = pop;
- croak 'subroutine "mimetype" needs a filename as argument' unless defined $file;
- return
- inodetype($file) ||
- globs($file) ||
- default($file);
+ my $file = pop;
+ croak 'subroutine "mimetype" needs a filename as argument' unless defined $file;
+ return
+ inodetype($file) ||
+ globs($file) ||
+ default($file);
}
sub inodetype {
- my $file = pop;
- print STDERR "> Checking inode type\n" if $DEBUG;
- lstat $file or return undef;
- return undef if -f _;
- my $t = (-l $file) ? 'inode/symlink' : # Win32 does not like '_' here
- (-d _) ? 'inode/directory' :
- (-p _) ? 'inode/fifo' :
- (-c _) ? 'inode/chardevice' :
- (-b _) ? 'inode/blockdevice' :
- (-S _) ? 'inode/socket' : '' ;
- if ($t eq 'inode/directory') { # compare devices to detect mount-points
- my $dev = (stat _)[0]; # device of the node under investigation
- $file = File::Spec->rel2abs($file); # get full path
- my @dirs = File::Spec->splitdir($file);
- $file = File::Spec->catfile(@dirs); # removes trailing '/' or equivalent
- return $t if -l $file; # parent can be on other dev for links
- pop @dirs;
- my $dir = File::Spec->catdir(@dirs); # parent dir
- $t = 'inode/mount-point' unless (stat $dir)[0] == $dev; # compare devices
- return $t;
- }
- else { return $t ? $t : undef }
+ my $file = pop;
+ print STDERR "> Checking inode type\n" if $DEBUG;
+ lstat $file or return undef;
+ return undef if -f _;
+ my $t = (-l $file) ? 'inode/symlink' : # Win32 does not like '_' here
+ (-d _) ? 'inode/directory' :
+ (-p _) ? 'inode/fifo' :
+ (-c _) ? 'inode/chardevice' :
+ (-b _) ? 'inode/blockdevice' :
+ (-S _) ? 'inode/socket' : '' ;
+ if ($t eq 'inode/directory') { # compare devices to detect mount-points
+ my $dev = (stat _)[0]; # device of the node under investigation
+ $file = File::Spec->rel2abs($file); # get full path
+ my @dirs = File::Spec->splitdir($file);
+ $file = File::Spec->catfile(@dirs); # removes trailing '/' or equivalent
+ return $t if -l $file; # parent can be on other dev for links
+ pop @dirs;
+ my $dir = File::Spec->catdir(@dirs); # parent dir
+ $t = 'inode/mount-point' unless (stat $dir)[0] == $dev; # compare devices
+ return $t;
+ }
+ else { return $t ? $t : undef }
}
sub globs {
- my $file = pop;
- croak 'subroutine "globs" needs a filename as argument' unless defined $file;
- rehash() unless $_hashed;
- (undef, undef, $file) = File::Spec->splitpath($file); # remove path
- print STDERR "> Checking globs for basename '$file'\n" if $DEBUG;
-
- return $literal{$file} if exists $literal{$file};
-
- if ($file =~ /\.(\w+(\.\w+)*)$/) {
- my @ext = split /\./, $1;
- while (@ext) {
- my $ext = join('.', @ext);
- print STDERR "> Checking for extension '.$ext'\n" if $DEBUG;
- warn "WARNING: wantarray behaviour of globs() will change in the future.\n" if wantarray;
- return wantarray
- ? ($extension{$ext}, $ext)
- : $extension{$ext}
- if exists $extension{$ext};
- shift @ext;
- }
- }
-
- for (@globs) {
- next unless $file =~ $_->[1];
- print STDERR "> This file name matches \"$_->[0]\"\n" if $DEBUG;
- return $_->[2];
- }
-
- return globs(lc $file) if $file =~ /[A-Z]/; # recurs
- return undef;
+ my $file = pop;
+ croak 'subroutine "globs" needs a filename as argument' unless defined $file;
+ rehash() unless $_hashed;
+ (undef, undef, $file) = File::Spec->splitpath($file); # remove path
+ print STDERR "> Checking globs for basename '$file'\n" if $DEBUG;
+
+ return $literal{$file} if exists $literal{$file};
+
+ if ($file =~ /\.(\w+(\.\w+)*)$/) {
+ my @ext = split /\./, $1;
+ while (@ext) {
+ my $ext = join('.', @ext);
+ print STDERR "> Checking for extension '.$ext'\n" if $DEBUG;
+ carp "WARNING: wantarray behaviour of globs() will change in the future.\n" if wantarray;
+ return wantarray
+ ? ($extension{$ext}, $ext)
+ : $extension{$ext}
+ if exists $extension{$ext};
+ shift @ext;
+ }
+ }
+
+ for (@globs) {
+ next unless $file =~ $_->[1];
+ print STDERR "> This file name matches \"$_->[0]\"\n" if $DEBUG;
+ return $_->[2];
+ }
+
+ return globs(lc $file) if $file =~ /[A-Z]/; # recurs
+ return undef;
}
sub default {
- my $file = pop;
- croak 'subroutine "default" needs a filename as argument' unless defined $file;
-
- my $line;
- unless (ref $file) {
- return undef unless -f $file;
- print STDERR "> File exists, trying default method\n" if $DEBUG;
- return 'text/plain' if -z $file;
-
- open FILE, '<', $file or return undef;
- binmode FILE, ':utf8' unless $] < 5.008;
- read FILE, $line, 32;
- close FILE;
- }
- elsif (ref $file eq 'Path::Tiny') {
- return undef unless $file->exists;
- print STDERR "> File is Path::Tiny object and exists, "
- . "trying default method\n" if $DEBUG;
- open my $fh, '<', $file or return undef;
- binmode FILE, ':utf8' unless $] < 5.008;
- read $fh, $line, 32;
- close $fh;
- }
- else {
- print STDERR "> Trying default method on object\n" if $DEBUG;
-
- $file->seek(0, SEEK_SET);
- $file->read($line, 32);
- }
-
- {
- no warnings; # warnings can be thrown when input not ascii
- if ($] < 5.008 or ! utf8::valid($line)) {
- use bytes; # avoid invalid utf8 chars
- $line =~ s/\s//g; # \m, \n and \t are also control chars
- return 'text/plain' unless $line =~ /[\x00-\x1F\x7F]/;
- }
- else {
- # use perl to do something intelligent for ascii & utf8
- return 'text/plain' unless $line =~ /[^[:print:]\s]/;
- }
- }
- print STDERR "> First 10 bytes of the file contain control chars\n" if $DEBUG;
- return 'application/octet-stream';
+ my $file = pop;
+ croak 'subroutine "default" needs a filename as argument' unless defined $file;
+
+ my $line;
+ unless (ref $file) {
+ return undef unless -f $file;
+ print STDERR "> File exists, trying default method\n" if $DEBUG;
+ return 'text/plain' if -z $file;
+
+ open FILE, '<', $file or return undef;
+ binmode FILE, ':utf8' unless $] < 5.008;
+ read FILE, $line, 32;
+ close FILE;
+ }
+ elsif (ref $file eq 'Path::Tiny') {
+ return undef unless $file->exists;
+ print STDERR "> File is Path::Tiny object and exists, "
+ . "trying default method\n" if $DEBUG;
+ open my $fh, '<', $file or return undef;
+ binmode FILE, ':utf8' unless $] < 5.008;
+ read $fh, $line, 32;
+ close $fh;
+ }
+ else {
+ print STDERR "> Trying default method on object\n" if $DEBUG;
+
+ $file->seek(0, SEEK_SET);
+ $file->read($line, 32);
+ }
+
+ {
+ no warnings; # warnings can be thrown when input not ascii
+ if ($] < 5.008 or ! utf8::valid($line)) {
+ use bytes; # avoid invalid utf8 chars
+ $line =~ s/\s//g; # \m, \n and \t are also control chars
+ return 'text/plain' unless $line =~ /[\x00-\x1F\x7F]/;
+ }
+ else {
+ # use perl to do something intelligent for ascii & utf8
+ return 'text/plain' unless $line =~ /[^[:print:]\s]/;
+ }
+ }
+ print STDERR "> First 10 bytes of the file contain control chars\n" if $DEBUG;
+ return 'application/octet-stream';
}
sub rehash {
- (@globs, %literal, %extension, %mime2ext) = (); # clear all data
- local $_; # limit scope of $_ ... :S
- my @globfiles = @DIRS
- ? ( grep {-e $_ && -r $_} map "$_/globs", @DIRS )
- : ( reverse data_files('mime/globs') );
- print STDERR << 'EOT' unless @globfiles;
-WARNING: You don't seem to have a mime-info database. The
-shared-mime-info package is available from http://freedesktop.org/ .
-EOT
- my @done;
- for my $file (@globfiles) {
- next if grep {$file eq $_} @done;
- _hash_globs($file);
- push @done, $file;
- }
- $_hashed = 1;
+ (@globs, %literal, %extension, %mime2ext) = (); # clear all data
+ local $_; # limit scope of $_ ... :S
+ my @globfiles = @DIRS
+ ? ( grep {-e $_ && -r $_} map "$_/globs", @DIRS )
+ : ( reverse data_files('mime/globs') );
+ if (@globfiles) {
+ $_has_mimeinfo_database = 1;
+ } else {
+ carp "WARNING: You don't seem to have a mime-info database. " .
+ "The shared-mime-info package is available from http://freedesktop.org/";
+ }
+ my @done;
+ for my $file (@globfiles) {
+ next if grep {$file eq $_} @done;
+ _hash_globs($file);
+ push @done, $file;
+ }
+ $_hashed = 1;
}
sub _hash_globs {
- my $file = shift;
- open GLOB, '<', $file || croak "Could not open file '$file' for reading" ;
- binmode GLOB, ':utf8' unless $] < 5.008;
- my ($string, $glob);
- while (<GLOB>) {
- next if /^\s*#/ or ! /\S/; # skip comments and empty lines
- chomp;
- ($string, $glob) = split /:/, $_, 2;
- unless ($glob =~ /[\?\*\[]/) { $literal{$glob} = $string }
- elsif ($glob =~ /^\*\.(\w+(\.\w+)*)$/) {
- $extension{$1} = $string unless exists $extension{$1};
- $mime2ext{$string} = [] if !defined($mime2ext{$string});
- push @{$mime2ext{$string}}, $1;
- } else { unshift @globs, [$glob, _glob_to_regexp($glob), $string] }
- }
- close GLOB || croak "Could not open file '$file' for reading" ;
+ my $file = shift;
+ open GLOB, '<', $file || croak "Could not open file '$file' for reading" ;
+ binmode GLOB, ':utf8' unless $] < 5.008;
+ my ($string, $glob);
+ while (<GLOB>) {
+ next if /^\s*#/ or ! /\S/; # skip comments and empty lines
+ chomp;
+ ($string, $glob) = split /:/, $_, 2;
+ unless ($glob =~ /[\?\*\[]/) { $literal{$glob} = $string }
+ elsif ($glob =~ /^\*\.(\w+(\.\w+)*)$/) {
+ $extension{$1} = $string unless exists $extension{$1};
+ $mime2ext{$string} = [] if !defined($mime2ext{$string});
+ push @{$mime2ext{$string}}, $1;
+ } else { unshift @globs, [$glob, _glob_to_regexp($glob), $string] }
+ }
+ close GLOB || croak "Could not open file '$file' for reading" ;
}
sub _glob_to_regexp {
- my $glob = shift;
- $glob =~ s/\./\\./g;
- $glob =~ s/([?*])/.$1/g;
- $glob =~ s/([^\w\/\\\.\?\*\[\]])/\\$1/g;
- qr/^$glob$/;
+ my $glob = shift;
+ $glob =~ s/\./\\./g;
+ $glob =~ s/([?*])/.$1/g;
+ $glob =~ s/([^\w\/\\\.\?\*\[\]])/\\$1/g;
+ qr/^$glob$/;
+}
+
+sub has_mimeinfo_database {
+ rehash() if (!$_hashed);
+ return $_has_mimeinfo_database;
}
sub extensions {
- my $mimet = mimetype_canon(pop @_);
- rehash() unless $_hashed;
+ my $mimet = mimetype_canon(pop @_);
+ rehash() unless $_hashed;
my $ref = $mime2ext{$mimet} if exists $mime2ext{$mimet};
- return $ref ? @{$ref} : undef if wantarray;
+ return $ref ? @{$ref} : undef if wantarray;
return $ref ? @{$ref}[0] : '';
}
sub describe {
- shift if ref $_[0];
- my ($mt, $lang) = @_;
- croak 'subroutine "describe" needs a mimetype as argument' unless $mt;
- $mt = mimetype_canon($mt);
- $lang = $LANG unless defined $lang;
- my $att = $lang ? qq{xml:lang="$lang"} : '';
- my $desc;
- my @descfiles = @DIRS
- ? ( grep {-e $_ && -r $_} map "$_/$mt.xml", @DIRS )
- : ( reverse data_files('mime', split '/', "$mt.xml") ) ;
- for my $file (@descfiles) {
- $desc = ''; # if a file was found, return at least empty string
- open XML, '<', $file || croak "Could not open file '$file' for reading";
- binmode XML, ':utf8' unless $] < 5.008;
- while (<XML>) {
- next unless m!<comment\s*$att>(.*?)</comment>!;
- $desc = $1;
- last;
- }
- close XML || croak "Could not open file '$file' for reading";
- last if $desc;
- }
- return $desc;
+ shift if ref $_[0];
+ my ($mt, $lang) = @_;
+ croak 'subroutine "describe" needs a mimetype as argument' unless $mt;
+ $mt = mimetype_canon($mt);
+ $lang = $LANG unless defined $lang;
+ my $att = $lang ? qq{xml:lang="$lang"} : '';
+ my $desc;
+ my @descfiles = @DIRS
+ ? ( grep {-e $_ && -r $_} map "$_/$mt.xml", @DIRS )
+ : ( reverse data_files('mime', split '/', "$mt.xml") ) ;
+ for my $file (@descfiles) {
+ $desc = ''; # if a file was found, return at least empty string
+ open XML, '<', $file || croak "Could not open file '$file' for reading";
+ binmode XML, ':utf8' unless $] < 5.008;
+ while (<XML>) {
+ next unless m!<comment\s*$att>(.*?)</comment>!;
+ $desc = $1;
+ last;
+ }
+ close XML || croak "Could not open file '$file' for reading";
+ last if $desc;
+ }
+ return $desc;
}
sub mimetype_canon {
- my $mimet = pop;
- croak 'mimetype_canon needs argument' unless defined $mimet;
- rehash_aliases() unless $_hashed_aliases;
- return exists($aliases{$mimet}) ? $aliases{$mimet} : $mimet;
+ my $mimet = pop;
+ croak 'mimetype_canon needs argument' unless defined $mimet;
+ rehash_aliases() unless $_hashed_aliases;
+ return exists($aliases{$mimet}) ? $aliases{$mimet} : $mimet;
}
sub rehash_aliases {
- %aliases = _read_map_files('aliases');
- $_hashed_aliases++;
+ %aliases = _read_map_files('aliases');
+ $_hashed_aliases++;
}
sub _read_map_files {
- my ($name, $list) = @_;
- my @files = @DIRS
- ? ( grep {-e $_ && -r $_} map "$_/$name", @DIRS )
- : ( reverse data_files("mime/$name") );
- my (@done, %map);
- for my $file (@files) {
- next if grep {$_ eq $file} @done;
- open MAP, '<', $file || croak "Could not open file '$file' for reading";
- binmode MAP, ':utf8' unless $] < 5.008;
- while (my $line = <MAP>) {
- next unless $line =~ m/\S/; # skip empty lines
- next if $line =~ m/^\s*#/; # skip comment lines
- chomp $line;
- my ($k, $v) = split m/\s+/, $line, 2;
- if ($list) {
- $map{$k} = [] unless $map{$k};
- push @{$map{$k}}, $v;
- }
- else { $map{$k} = $v }
- }
- close MAP;
- push @done, $file;
- }
- return %map;
+ my ($name, $list) = @_;
+ my @files = @DIRS
+ ? ( grep {-e $_ && -r $_} map "$_/$name", @DIRS )
+ : ( reverse data_files("mime/$name") );
+ my (@done, %map);
+ for my $file (@files) {
+ next if grep {$_ eq $file} @done;
+ open MAP, '<', $file || croak "Could not open file '$file' for reading";
+ binmode MAP, ':utf8' unless $] < 5.008;
+ while (my $line = <MAP>) {
+ next unless $line =~ m/\S/; # skip empty lines
+ next if $line =~ m/^\s*#/; # skip comment lines
+ chomp $line;
+ my ($k, $v) = split m/\s+/, $line, 2;
+ if ($list) {
+ $map{$k} = [] unless $map{$k};
+ push @{$map{$k}}, $v;
+ }
+ else { $map{$k} = $v }
+ }
+ close MAP;
+ push @done, $file;
+ }
+ return %map;
}
sub mimetype_isa {
- my $parent = pop || croak 'mimetype_isa needs argument';
- my $mimet = pop;
- if (ref $mimet or ! defined $mimet) {
- $mimet = mimetype_canon($parent);
- undef $parent;
- }
- else {
- $mimet = mimetype_canon($mimet);
- $parent = mimetype_canon($parent);
- }
- rehash_subclasses() unless $_hashed_subclasses;
-
- my @subc;
- push @subc, 'inode/directory' if $mimet eq 'inode/mount-point';
- push @subc, @{$subclasses{$mimet}} if exists $subclasses{$mimet};
- push @subc, 'text/plain' if $mimet =~ m#^text/#;
- push @subc, 'application/octet-stream' unless $mimet =~ m#^inode/#;
-
- return $parent ? scalar(grep {$_ eq $parent} @subc) : @subc;
+ my $parent = pop || croak 'mimetype_isa needs argument';
+ my $mimet = pop;
+ if (ref $mimet or ! defined $mimet) {
+ $mimet = mimetype_canon($parent);
+ undef $parent;
+ }
+ else {
+ $mimet = mimetype_canon($mimet);
+ $parent = mimetype_canon($parent);
+ }
+ rehash_subclasses() unless $_hashed_subclasses;
+
+ my @subc;
+ push @subc, 'inode/directory' if $mimet eq 'inode/mount-point';
+ push @subc, @{$subclasses{$mimet}} if exists $subclasses{$mimet};
+ push @subc, 'text/plain' if $mimet =~ m#^text/#;
+ push @subc, 'application/octet-stream' unless $mimet =~ m#^inode/#;
+
+ return $parent ? scalar(grep {$_ eq $parent} @subc) : @subc;
}
sub rehash_subclasses {
- %subclasses = _read_map_files('subclasses', 'LIST');
- $_hashed_subclasses++;
+ %subclasses = _read_map_files('subclasses', 'LIST');
+ $_hashed_subclasses++;
}
1;
@@ -409,6 +417,15 @@ the first one.
This method checks the subclasses table and applies a few rules for implicit
subclasses.
+=item C<has_mimeinfo_database()>
+
+Check if there are mimeinfo database files available; returns 1 on success.
+If you don't have the shared-mime-info package installed or not in the PATH or
+C<@File::MimeInfo::DIRS> does not contain database directories, you will not get
+the successful reply.
+
+New in version 0.30.
+
=item C<rehash()>
Rehash the data files. Glob information is preparsed when this method is called.
@@ -454,6 +471,14 @@ in a straightforward manner only utf8 is supported (because the spec recommends
This module does not yet check extended attributes for a mimetype.
Patches for this are very welcome.
+This module uses the FreeDesktop.org shared mime info database. On your desktop
+linux this is typically pre-installed so it's not a problem. On your server
+you can install the shared-mime-info package via apt or dnf or apk or whatnot.
+
+To install on macOS, you can install it like this:
+
+ brew install shared-mime-info
+
=head1 AUTHOR
Jaap Karssenberg E<lt>pardus@cpan.orgE<gt>
diff --git a/lib/File/MimeInfo/Applications.pm b/lib/File/MimeInfo/Applications.pm
index e6142f6..35279a8 100644
--- a/lib/File/MimeInfo/Applications.pm
+++ b/lib/File/MimeInfo/Applications.pm
@@ -1,6 +1,7 @@
package File::MimeInfo::Applications;
use strict;
+use warnings;
use Carp;
use File::Spec;
use File::BaseDir qw/config_home config_dirs data_home data_dirs data_files/;
@@ -8,12 +9,12 @@ use File::MimeInfo qw/mimetype_canon mimetype_isa/;
use File::DesktopEntry;
require Exporter;
-our $VERSION = '0.29';
+our $VERSION = '0.30';
our @ISA = qw(Exporter);
our @EXPORT = qw(
- mime_applications mime_applications_all
- mime_applications_set_default mime_applications_set_custom
+ mime_applications mime_applications_all
+ mime_applications_set_default mime_applications_set_custom
);
print STDERR << 'EOT' unless data_files(qw/applications mimeinfo.cache/);
@@ -25,179 +26,179 @@ http://freedesktop.org/wiki/Software/desktop-file-utils/
EOT
sub mime_applications {
- croak "usage: mime_applications(MIMETYPE)" unless @_ == 1;
- my $mime = mimetype_canon(shift @_);
- local $Carp::CarpLevel = $Carp::CarpLevel + 1;
- return wantarray ? (_default($mime), _others($mime)) : _default($mime);
+ croak "usage: mime_applications(MIMETYPE)" unless @_ == 1;
+ my $mime = mimetype_canon(shift @_);
+ local $Carp::CarpLevel = $Carp::CarpLevel + 1;
+ return wantarray ? (_default($mime), _others($mime)) : _default($mime);
}
sub mime_applications_all {
- croak "usage: mime_applications(MIMETYPE)" unless @_ == 1;
- my $mime = shift;
- return mime_applications($mime),
- grep defined($_), map mime_applications($_), mimetype_isa($mime);
+ croak "usage: mime_applications(MIMETYPE)" unless @_ == 1;
+ my $mime = shift;
+ return mime_applications($mime),
+ grep defined($_), map mime_applications($_), mimetype_isa($mime);
}
sub mime_applications_set_default {
- croak "usage: mime_applications_set_default(MIMETYPE, APPLICATION)"
- unless @_ == 2;
- my ($mimetype, $desktop_file) = @_;
- (undef, undef, $desktop_file) =
- File::Spec->splitpath($desktop_file->{file})
- if ref $desktop_file;
- croak "missing desktop entry filename for application"
- unless length $desktop_file;
- $desktop_file .= '.desktop' unless $desktop_file =~ /\.desktop$/;
- _write_list($mimetype, $desktop_file);
+ croak "usage: mime_applications_set_default(MIMETYPE, APPLICATION)"
+ unless @_ == 2;
+ my ($mimetype, $desktop_file) = @_;
+ (undef, undef, $desktop_file) =
+ File::Spec->splitpath($desktop_file->{file})
+ if ref $desktop_file;
+ croak "missing desktop entry filename for application"
+ unless length $desktop_file;
+ $desktop_file .= '.desktop' unless $desktop_file =~ /\.desktop$/;
+ _write_list($mimetype, $desktop_file);
}
sub mime_applications_set_custom {
- croak "usage: mime_applications_set_custom(MIMETYPE, COMMAND)"
- unless @_ == 2;
- my ($mimetype, $command) = @_;
- $command =~ /(\w+)/;
- my $word = $1 or croak "COMMAND does not contain a word !?";
-
- # Algorithm to generate name copied from other implementations
- my $i = 1;
- my $desktop_file =
- data_home('applications', $word.'-usercreated-'.$i.'.desktop');
- while (-e $desktop_file) {
- $i++;
- $desktop_file =
- data_home('applications', $word.'-usercreated-'.$i.'.desktop');
- }
-
- my $object = File::DesktopEntry->new();
- $object->set(
- Type => 'Application',
- Name => $word,
- NoDisplay => 'true',
- Exec => $command,
- );
- my (undef, undef, $df) = File::Spec->splitpath($desktop_file);
- _write_list($mimetype, $df); # creates dir if needed
- $object->write($desktop_file);
- return $object;
+ croak "usage: mime_applications_set_custom(MIMETYPE, COMMAND)"
+ unless @_ == 2;
+ my ($mimetype, $command) = @_;
+ $command =~ /(\w+)/;
+ my $word = $1 or croak "COMMAND does not contain a word !?";
+
+ # Algorithm to generate name copied from other implementations
+ my $i = 1;
+ my $desktop_file =
+ data_home('applications', $word.'-usercreated-'.$i.'.desktop');
+ while (-e $desktop_file) {
+ $i++;
+ $desktop_file =
+ data_home('applications', $word.'-usercreated-'.$i.'.desktop');
+ }
+
+ my $object = File::DesktopEntry->new();
+ $object->set(
+ Type => 'Application',
+ Name => $word,
+ NoDisplay => 'true',
+ Exec => $command,
+ );
+ my (undef, undef, $df) = File::Spec->splitpath($desktop_file);
+ _write_list($mimetype, $df); # creates dir if needed
+ $object->write($desktop_file);
+ return $object;
}
sub _default {
- my $mimetype = shift;
-
- my $user = config_home(qw/mimeapps.list/);
- my $system = config_dirs(qw/mimeapps.list/);
- my $deprecated = data_home(qw/applications mimeapps.list/);
- my $distro = data_dirs(qw/applications mimeapps.list/);
- my $legacy = data_home(qw/applications defaults.list/);
-
- unless ( ( -f $user
- || -f $system
- || -f $deprecated
- || -f $distro
- || -f $legacy )
- && -r _ ) {
- return undef;
- }
-
- $Carp::CarpLevel++;
- my @list =
- _read_list($mimetype, $user, $system, $deprecated, $distro, $legacy);
- my $desktop_file = _find_file(reverse @list);
- $Carp::CarpLevel--;
-
- return $desktop_file;
+ my $mimetype = shift;
+
+ my $user = config_home(qw/mimeapps.list/);
+ my $system = config_dirs(qw/mimeapps.list/);
+ my $deprecated = data_home(qw/applications mimeapps.list/);
+ my $distro = data_dirs(qw/applications mimeapps.list/);
+ my $legacy = data_home(qw/applications defaults.list/);
+
+ unless ( ( -f $user
+ || ($system && -f $system)
+ || ($deprecated && -f $deprecated)
+ || ($distro && -f $distro)
+ || ($legacy && -f $legacy) )
+ && -r _ ) {
+ return undef;
+ }
+
+ $Carp::CarpLevel++;
+ my @list =
+ _read_list($mimetype, $user, $system, $deprecated, $distro, $legacy);
+ my $desktop_file = _find_file(reverse @list);
+ $Carp::CarpLevel--;
+
+ return $desktop_file;
}
sub _others {
- my $mimetype = shift;
-
- $Carp::CarpLevel++;
- my (@list, @done);
- for my $dir (data_dirs('applications')) {
- my $cache = File::Spec->catfile($dir, 'mimeinfo.cache');
- next if grep {$_ eq $cache} @done;
- push @done, $cache;
- next unless -f $cache and -r _;
- for (_read_list($mimetype, $cache)) {
- my $file = File::Spec->catfile($dir, $_);
- next unless -f $file and -r _;
- push @list, File::DesktopEntry->new($file);
- }
- }
- $Carp::CarpLevel--;
-
- return @list;
+ my $mimetype = shift;
+
+ $Carp::CarpLevel++;
+ my (@list, @done);
+ for my $dir (data_dirs('applications')) {
+ my $cache = File::Spec->catfile($dir, 'mimeinfo.cache');
+ next if grep {$_ eq $cache} @done;
+ push @done, $cache;
+ next unless -f $cache and -r _;
+ for (_read_list($mimetype, $cache)) {
+ my $file = File::Spec->catfile($dir, $_);
+ next unless -f $file and -r _;
+ push @list, File::DesktopEntry->new($file);
+ }
+ }
+ $Carp::CarpLevel--;
+
+ return @list;
}
sub _read_list { # read list with "mime/type=foo.desktop;bar.desktop" format
- my $mimetype = shift;
-
- my @list;
- my $succeeded;
-
- for my $file (@_) {
- if (open LIST, '<', $file) {
- $succeeded = 1;
- while (<LIST>) {
- /^\Q$mimetype\E=(.*)$/ or next;
- push @list, grep defined($_), split ';', $1;
- }
- close LIST;
- }
- }
-
- unless ($succeeded) {
- croak "Could not read any defaults, tried:\n" . join("\t\n", @_);
- }
-
- return @list;
+ my $mimetype = shift;
+
+ my @list;
+ my $succeeded;
+
+ for my $file (@_) {
+ if (open LIST, '<', $file) {
+ $succeeded = 1;
+ while (<LIST>) {
+ /^\Q$mimetype\E=(.*)$/ or next;
+ push @list, grep defined($_), split ';', $1;
+ }
+ close LIST;
+ }
+ }
+
+ unless ($succeeded) {
+ croak "Could not read any defaults, tried:\n" . join("\t\n", @_);
+ }
+
+ return @list;
}
sub _write_list {
- my ($mimetype, $desktop_file) = @_;
- my $file = config_home(qw/mimeapps.list/);
- my $text;
- if (-f $file) {
- open LIST, '<', $file or croak "Could not read file: $file";
- while (<LIST>) {
- $text .= $_ unless /^\Q$mimetype\E=/;
- }
- close LIST;
- $text =~ s/[\n\r]?$/\n/; # just to be sure
- }
- else {
- _mkdir($file);
- $text = "[Default Applications]\n";
- }
-
- open LIST, '>', $file or croak "Could not write file: $file";
- print LIST $text;
- print LIST "$mimetype=$desktop_file;\n";
- close LIST or croak "Could not write file: $file";
+ my ($mimetype, $desktop_file) = @_;
+ my $file = config_home(qw/mimeapps.list/);
+ my $text;
+ if (-f $file) {
+ open LIST, '<', $file or croak "Could not read file: $file";
+ while (<LIST>) {
+ $text .= $_ unless /^\Q$mimetype\E=/;
+ }
+ close LIST;
+ $text =~ s/[\n\r]?$/\n/; # just to be sure
+ }
+ else {
+ _mkdir($file);
+ $text = "[Default Applications]\n";
+ }
+
+ open LIST, '>', $file or croak "Could not write file: $file";
+ print LIST $text;
+ print LIST "$mimetype=$desktop_file;\n";
+ close LIST or croak "Could not write file: $file";
}
sub _find_file {
- my @list = shift;
- for (@list) {
- my $file = data_files('applications', $_);
- return File::DesktopEntry->new($file) if $file;
- }
- return undef;
+ my @list = shift;
+ for (@list) {
+ my $file = data_files('applications', $_);
+ return File::DesktopEntry->new($file) if $file;
+ }
+ return undef;
}
sub _mkdir {
- my $dir = shift;
- return if -d $dir;
-
- my ($vol, $dirs, undef) = File::Spec->splitpath($dir);
- my @dirs = File::Spec->splitdir($dirs);
- my $path = File::Spec->catpath($vol, shift @dirs);
- while (@dirs) {
- mkdir $path; # fails silently
- $path = File::Spec->catdir($path, shift @dirs);
- }
-
- die "Could not create dir: $path\n" unless -d $path;
+ my $dir = shift;
+ return if -d $dir;
+
+ my ($vol, $dirs, undef) = File::Spec->splitpath($dir);
+ my @dirs = File::Spec->splitdir($dirs);
+ my $path = File::Spec->catpath($vol, shift @dirs);
+ while (@dirs) {
+ mkdir $path; # fails silently
+ $path = File::Spec->catdir($path, shift @dirs);
+ }
+
+ die "Could not create dir: $path\n" unless -d $path;
}
1;
@@ -215,16 +216,16 @@ File::MimeInfo::Applications - Find programs to open a file by mimetype
my $file = '/foo/bar';
my $mimetype = mimetype($file)
- || die "Could not find mimetype for $file\n";
+ || die "Could not find mimetype for $file\n";
my ($default, @other) = mime_applications($mimetype);
if (defined $default) {
- $default->system($file)
+ $default->system($file)
}
else {
- # prompt user with choice from @others
- # ...
+ # prompt user with choice from @others
+ # ...
}
=head1 DESCRIPTION
diff --git a/lib/File/MimeInfo/Magic.pm b/lib/File/MimeInfo/Magic.pm
index 3e96f09..23cac41 100644
--- a/lib/File/MimeInfo/Magic.pm
+++ b/lib/File/MimeInfo/Magic.pm
@@ -8,16 +8,16 @@ require File::MimeInfo;
require Exporter;
BEGIN {
- no strict "refs";
- for (qw/extensions describe globs inodetype default/) {
- *{$_} = \&{"File::MimeInfo::$_"};
- }
+ no strict "refs";
+ for (qw/extensions describe globs inodetype default/) {
+ *{$_} = \&{"File::MimeInfo::$_"};
+ }
}
our @ISA = qw(Exporter File::MimeInfo);
our @EXPORT = qw(mimetype);
our @EXPORT_OK = qw(extensions describe globs inodetype magic);
-our $VERSION = '0.29';
+our $VERSION = '0.30';
our $DEBUG;
our $_hashed = 0;
@@ -29,222 +29,222 @@ our (@magic_80, @magic);
# filehandle in order to do magic mimetyping
sub mimetype {
- my $file = pop;
- croak 'subroutine "mimetype" needs a filename as argument' unless defined $file;
+ my $file = pop;
+ croak 'subroutine "mimetype" needs a filename as argument' unless defined $file;
- return magic($file) || default($file) if ref $file;
- return &File::MimeInfo::mimetype($file) unless -s $file and -r _;
+ return magic($file) || default($file) if ref $file;
+ return &File::MimeInfo::mimetype($file) unless -s $file and -r _;
- my ($mimet, $fh);
- return $mimet if $mimet = inodetype($file);
+ my ($mimet, $fh);
+ return $mimet if $mimet = inodetype($file);
- ($mimet, $fh) = _magic($file, \@magic_80); # high priority rules
- return $mimet if $mimet;
+ ($mimet, $fh) = _magic($file, \@magic_80); # high priority rules
+ return $mimet if $mimet;
- return $mimet if $mimet = globs($file);
+ return $mimet if $mimet = globs($file);
- ($mimet, $fh) = _magic($fh, \@magic); # lower priority rules
- close $fh if ref $fh;
+ ($mimet, $fh) = _magic($fh, \@magic); # lower priority rules
+ close $fh if ref $fh;
- return $mimet if $mimet;
- return default($file);
+ return $mimet if $mimet;
+ return default($file);
}
sub magic {
- my $file = pop;
- croak 'subroutine "magic" needs a filename as argument' unless defined $file;
- return undef unless ref($file) || -s $file;
- print STDERR "> Checking all magic rules\n" if $DEBUG;
+ my $file = pop;
+ croak 'subroutine "magic" needs a filename as argument' unless defined $file;
+ return undef unless ref($file) || -s $file;
+ print STDERR "> Checking all magic rules\n" if $DEBUG;
- my ($mimet, $fh) = _magic($file, \@magic_80, \@magic);
- close $fh unless ref $file;
+ my ($mimet, $fh) = _magic($file, \@magic_80, \@magic);
+ close $fh unless ref $file;
- return $mimet;
+ return $mimet;
}
sub _magic {
- my ($file, @rules) = @_;
- _rehash() unless $_hashed;
-
- my $fh;
- unless (ref $file) {
- open $fh, '<', $file or return undef;
- binmode $fh;
- }
- else { $fh = $file }
-
- for my $type (map @$_, @rules) {
- for (2..$#$type) {
- next unless _check_rule($$type[$_], $fh, 0);
- close $fh unless ref $file;
- return ($$type[1], $fh);
- }
- }
- return (undef, $fh);
+ my ($file, @rules) = @_;
+ _rehash() unless $_hashed;
+
+ my $fh;
+ unless (ref $file) {
+ open $fh, '<', $file or return undef;
+ binmode $fh;
+ }
+ else { $fh = $file }
+
+ for my $type (map @$_, @rules) {
+ for (2..$#$type) {
+ next unless _check_rule($$type[$_], $fh, 0);
+ close $fh unless ref $file;
+ return ($$type[1], $fh);
+ }
+ }
+ return (undef, $fh);
}
sub _check_rule {
- my ($ref, $fh, $lev) = @_;
- my $line;
-
- # Read
- if (ref $fh eq 'GLOB') {
- seek($fh, $$ref[0], SEEK_SET); # seek offset
- read($fh, $line, $$ref[1]); # read max length
- }
- else { # allowing for IO::Something
- $fh->seek($$ref[0], SEEK_SET); # seek offset
- $fh->read($line, $$ref[1]); # read max length
- }
-
- # Match regex
- $line = unpack 'b*', $line if $$ref[2]; # unpack to bits if using mask
- return undef unless $line =~ $$ref[3]; # match regex
- print STDERR '>', '>'x$lev, ' Value "', _escape_bytes($2),
- '" at offset ', $$ref[1]+length($1),
- " matches at $$ref[4]\n"
- if $DEBUG;
- return 1 unless $#$ref > 4;
-
- # Check nested rules and recurs
- for (5..$#$ref) {
- return 1 if _check_rule($$ref[$_], $fh, $lev+1);
- }
- print STDERR "> Failed nested rules\n" if $DEBUG && ! $lev;
- return 0;
+ my ($ref, $fh, $lev) = @_;
+ my $line;
+
+ # Read
+ if (ref $fh eq 'GLOB') {
+ seek($fh, $$ref[0], SEEK_SET); # seek offset
+ read($fh, $line, $$ref[1]); # read max length
+ }
+ else { # allowing for IO::Something
+ $fh->seek($$ref[0], SEEK_SET); # seek offset
+ $fh->read($line, $$ref[1]); # read max length
+ }
+
+ # Match regex
+ $line = unpack 'b*', $line if $$ref[2]; # unpack to bits if using mask
+ return undef unless $line =~ $$ref[3]; # match regex
+ print STDERR '>', '>'x$lev, ' Value "', _escape_bytes($2),
+ '" at offset ', $$ref[1]+length($1),
+ " matches at $$ref[4]\n"
+ if $DEBUG;
+ return 1 unless $#$ref > 4;
+
+ # Check nested rules and recurs
+ for (5..$#$ref) {
+ return 1 if _check_rule($$ref[$_], $fh, $lev+1);
+ }
+ print STDERR "> Failed nested rules\n" if $DEBUG && ! $lev;
+ return 0;
}
sub rehash {
- &File::MimeInfo::rehash();
- &_rehash();
- #use Data::Dumper;
- #print Dumper \@magic_80, \@magic;
+ &File::MimeInfo::rehash();
+ &_rehash();
+ #use Data::Dumper;
+ #print Dumper \@magic_80, \@magic;
}
sub _rehash {
- local $_; # limit scope of $_ ... :S
- ($max_buffer, @magic_80, @magic) = (32); # clear data
- my @magicfiles = @File::MimeInfo::DIRS
- ? ( grep {-e $_ && -r $_}
- map "$_/magic", @File::MimeInfo::DIRS )
- : ( reverse data_files('mime/magic') ) ;
- my @done;
- for my $file (@magicfiles) {
- next if grep {$file eq $_} @done;
- _hash_magic($file);
- push @done, $file;
- }
- @magic = sort {$$b[0] <=> $$a[0]} @magic;
- while ($magic[0][0] >= 80) {
- push @magic_80, shift @magic;
- }
- $_hashed = 1;
+ local $_; # limit scope of $_ ... :S
+ ($max_buffer, @magic_80, @magic) = (32); # clear data
+ my @magicfiles = @File::MimeInfo::DIRS
+ ? ( grep {-e $_ && -r $_}
+ map "$_/magic", @File::MimeInfo::DIRS )
+ : ( reverse data_files('mime/magic') ) ;
+ my @done;
+ for my $file (@magicfiles) {
+ next if grep {$file eq $_} @done;
+ _hash_magic($file);
+ push @done, $file;
+ }
+ @magic = sort {$$b[0] <=> $$a[0]} @magic;
+ while ($magic[0][0] >= 80) {
+ push @magic_80, shift @magic;
+ }
+ $_hashed = 1;
}
sub _hash_magic {
- my $file = shift;
-
- open MAGIC, '<', $file
- || croak "Could not open file '$file' for reading";
- binmode MAGIC;
- <MAGIC> eq "MIME-Magic\x00\n"
- or carp "Magic file '$file' doesn't seem to be a magic file";
- my $line = 1;
- while (<MAGIC>) {
- $line++;
-
- if (/^\[(\d+):(.*?)\]\n$/) {
- push @magic, [$1,$2];
- next;
- }
-
- s/^(\d*)>(\d+)=(.{2})//s
- || warn "$file line $line skipped\n" && next;
- my ($i, $o, $l) = ($1, $2, unpack 'n', $3);
- # indent, offset, value length
- while (length($_) <= $l) {
- $_ .= <MAGIC>;
- $line++;
- }
-
- my $v = substr $_, 0, $l, ''; # value
-
- /^(?:&(.{$l}))?(?:~(\d+))?(?:\+(\d+))?\n$/s
- || warn "$file line $line skipped\n" && next;
- my ($m, $w, $r) = ($1, $2 || 1, $3 || 1);
- # mask, word size, range
- my $mdef = defined $m;
-
- # possible big endian to little endian conversion
- # as a bonus perl also takes care of weird endian cases
- if ( $w != 1 ) {
- my ( $utpl, $ptpl );
- if ( 2 == $w ) {
- $v = pack 'S', unpack 'n', $v;
- $m = pack 'S', unpack 'n', $m if $mdef;
- }
- elsif ( 4 == $w ) {
- $v = pack 'L', unpack 'N', $v;
- $m = pack 'L', unpack 'N', $m if $mdef;
- }
- else {
- warn "Unsupported word size: $w octets ".
- " at $file line $line\n"
- }
- }
-
- my $end = $o + $l + $r - 1;
- $max_buffer = $end if $max_buffer < $end;
- my $ref = $i ? _find_branch($i) : $magic[-1];
- $r--; # 1-based => 0-based range for regex
- $r *= 8 if $mdef; # bytes => bits for matching a mask
- my $reg = '^'
- . ( $r ? "(.{0,$r}?)" : '()' )
- . ( $mdef ? '('. _mask_regex($v, $m) .')'
- : '('. quotemeta($v) .')' ) ;
- push @$ref, [
- $o, $end, # offset, offset+length+range
- $mdef, # boolean for mask
- qr/$reg/sm, # the regex to match
- undef # debug data
- ];
- $$ref[-1][-1] = "$file line $line" if $DEBUG;
- }
- close MAGIC;
+ my $file = shift;
+
+ open MAGIC, '<', $file
+ || croak "Could not open file '$file' for reading";
+ binmode MAGIC;
+ <MAGIC> eq "MIME-Magic\x00\n"
+ or carp "Magic file '$file' doesn't seem to be a magic file";
+ my $line = 1;
+ while (<MAGIC>) {
+ $line++;
+
+ if (/^\[(\d+):(.*?)\]\n$/) {
+ push @magic, [$1,$2];
+ next;
+ }
+
+ s/^(\d*)>(\d+)=(.{2})//s
+ || warn "$file line $line skipped\n" && next;
+ my ($i, $o, $l) = ($1, $2, unpack 'n', $3);
+ # indent, offset, value length
+ while (length($_) <= $l) {
+ $_ .= <MAGIC>;
+ $line++;
+ }
+
+ my $v = substr $_, 0, $l, ''; # value
+
+ /^(?:&(.{$l}))?(?:~(\d+))?(?:\+(\d+))?\n$/s
+ || warn "$file line $line skipped\n" && next;
+ my ($m, $w, $r) = ($1, $2 || 1, $3 || 1);
+ # mask, word size, range
+ my $mdef = defined $m;
+
+ # possible big endian to little endian conversion
+ # as a bonus perl also takes care of weird endian cases
+ if ( $w != 1 ) {
+ my ( $utpl, $ptpl );
+ if ( 2 == $w ) {
+ $v = pack 'S', unpack 'n', $v;
+ $m = pack 'S', unpack 'n', $m if $mdef;
+ }
+ elsif ( 4 == $w ) {
+ $v = pack 'L', unpack 'N', $v;
+ $m = pack 'L', unpack 'N', $m if $mdef;
+ }
+ else {
+ warn "Unsupported word size: $w octets ".
+ " at $file line $line\n"
+ }
+ }
+
+ my $end = $o + $l + $r - 1;
+ $max_buffer = $end if $max_buffer < $end;
+ my $ref = $i ? _find_branch($i) : $magic[-1];
+ $r--; # 1-based => 0-based range for regex
+ $r *= 8 if $mdef; # bytes => bits for matching a mask
+ my $reg = '^'
+ . ( $r ? "(.{0,$r}?)" : '()' )
+ . ( $mdef ? '('. _mask_regex($v, $m) .')'
+ : '('. quotemeta($v) .')' ) ;
+ push @$ref, [
+ $o, $end, # offset, offset+length+range
+ $mdef, # boolean for mask
+ qr/$reg/sm, # the regex to match
+ undef # debug data
+ ];
+ $$ref[-1][-1] = "$file line $line" if $DEBUG;
+ }
+ close MAGIC;
}
sub _find_branch { # finds last branch of tree of rules
- my $i = shift;
- my $ref = $magic[-1];
- for (1..$i) { $ref = $$ref[-1] }
- return $ref;
+ my $i = shift;
+ my $ref = $magic[-1];
+ for (1..$i) { $ref = $$ref[-1] }
+ return $ref;
}
sub _mask_regex { # build regex based on mask
- my ($v, $m) = @_;
- my @v = split '', unpack "b*", $v;
- my @m = split '', unpack "b*", $m;
- my $re = '';
- for (0 .. $#m) {
- $re .= $m[$_] ? $v[$_] : '.' ;
- # If $mask = 1 than ($input && $mask) will be same as $input
- # If $mask = 0 than ($input && $mask) is always 0
- # But $mask = 0 only makes sense if $value = 0
- # So if $mask = 0 we ignore that bit of $input
- }
- return $re;
+ my ($v, $m) = @_;
+ my @v = split '', unpack "b*", $v;
+ my @m = split '', unpack "b*", $m;
+ my $re = '';
+ for (0 .. $#m) {
+ $re .= $m[$_] ? $v[$_] : '.' ;
+ # If $mask = 1 than ($input && $mask) will be same as $input
+ # If $mask = 0 than ($input && $mask) is always 0
+ # But $mask = 0 only makes sense if $value = 0
+ # So if $mask = 0 we ignore that bit of $input
+ }
+ return $re;
}
sub _escape_bytes { # used for debug output
- my $string = shift;
- if ($string =~ /[\x00-\x1F\x7F]/) {
- $string = join '', map {
- my $o = ord($_);
- ($o < 32) ? '^' . chr($o + 64) :
- ($o == 127) ? '^?' : $_ ;
- } split '', $string;
- }
- return $string;
+ my $string = shift;
+ if ($string =~ /[\x00-\x1F\x7F]/) {
+ $string = join '', map {
+ my $o = ord($_);
+ ($o < 32) ? '^' . chr($o + 64) :
+ ($o == 127) ? '^?' : $_ ;
+ } split '', $string;
+ }
+ return $string;
}
1;
@@ -257,8 +257,8 @@ File::MimeInfo::Magic - Determine file type with magic
=head1 SYNOPSIS
- use File::MimeInfo::Magic;
- my $mime_type = mimetype($file);
+ use File::MimeInfo::Magic;
+ my $mime_type = mimetype($file);
=head1 DESCRIPTION
diff --git a/lib/File/MimeInfo/Rox.pm b/lib/File/MimeInfo/Rox.pm
index 17b0a17..22e06af 100644
--- a/lib/File/MimeInfo/Rox.pm
+++ b/lib/File/MimeInfo/Rox.pm
@@ -1,6 +1,7 @@
package File::MimeInfo::Rox;
use strict;
+use warnings;
use Carp;
use File::BaseDir qw/config_home data_dirs/;
use File::Spec;
@@ -10,74 +11,74 @@ our @ISA = qw(Exporter);
our @EXPORT = qw(mime_exec mime_system);
our @EXPORT_OK = qw(suggest_script_name);
our %EXPORT_TAGS = (magic => \@EXPORT);
-our $VERSION = '0.29';
+our $VERSION = '0.30';
our @choicespath = (
- config_home('rox.sourceforge.net'),
- File::Spec->catdir($ENV{HOME}, 'Choices'),
- data_dirs('Choices'),
+ config_home('rox.sourceforge.net'),
+ File::Spec->catdir($ENV{HOME}, 'Choices'),
+ data_dirs('Choices'),
);
our ($DEBUG);
sub import {
- my $parent = (grep {$_ eq q/:magic/} @_)
- ? q/File::MimeInfo::Magic/
- : q/File::MimeInfo/;
- eval "use $parent";
- die $@ if $@;
- goto \&Exporter::import;
+ my $parent = (grep {$_ eq q/:magic/} @_)
+ ? q/File::MimeInfo::Magic/
+ : q/File::MimeInfo/;
+ eval "use $parent";
+ die $@ if $@;
+ goto \&Exporter::import;
}
sub mime_system { _do_mime('system', @_) }
sub mime_exec { _do_mime('exec', @_) }
sub _do_mime {
- my ($act, $file, $mimet) = (shift, shift, shift);
+ my ($act, $file, $mimet) = (shift, shift, shift);
- $mimet ||= mimetype($file);
- return undef unless $mimet;
- print "Using mimetype: $mimet\n" if $DEBUG;
+ $mimet ||= mimetype($file);
+ return undef unless $mimet;
+ print "Using mimetype: $mimet\n" if $DEBUG;
- my $script = _locate_script($mimet);
- return undef unless $script;
+ my $script = _locate_script($mimet);
+ return undef unless $script;
- print "Going to $act: $script $file\n" if $DEBUG;
- ($act eq 'exec')
- ? exec($script, $file, @_)
- : (system($script, $file, @_) == 0)
- or croak "couldn't $act: $script $file";
- 42;
+ print "Going to $act: $script $file\n" if $DEBUG;
+ ($act eq 'exec')
+ ? exec($script, $file, @_)
+ : (system($script, $file, @_) == 0)
+ or croak "couldn't $act: $script $file";
+ 42;
}
sub _locate_script {
- my $mime = shift;
- $mime =~ /^(\w+)/;
- my $media = $1;
- $mime =~ s#/#_#;
- my @p = $ENV{CHOICESPATH}
- ? split(/:/, $ENV{CHOICESPATH})
- : (@choicespath);
- my $script;
- for (
- map("$_/MIME-types/$mime", @p),
- map("$_/MIME-types/$media", @p)
- ) {
- print "looking for: $_\n" if $DEBUG;
- next unless -e $_;
- $script = $_;
- last;
- }
- return undef unless $script;
- $script = "$script/AppRun" if -d $script;
- return -f $script ? $script : undef;
+ my $mime = shift;
+ $mime =~ /^(\w+)/;
+ my $media = $1;
+ $mime =~ s#/#_#;
+ my @p = $ENV{CHOICESPATH}
+ ? split(/:/, $ENV{CHOICESPATH})
+ : (@choicespath);
+ my $script;
+ for (
+ map("$_/MIME-types/$mime", @p),
+ map("$_/MIME-types/$media", @p)
+ ) {
+ print "looking for: $_\n" if $DEBUG;
+ next unless -e $_;
+ $script = $_;
+ last;
+ }
+ return undef unless $script;
+ $script = "$script/AppRun" if -d $script;
+ return -f $script ? $script : undef;
}
sub suggest_script_name {
- my $m = pop;
- $m =~ s#/#_#;
- my @p = $ENV{CHOICESPATH}
- ? split(/:/, $ENV{CHOICESPATH})
- : (@choicespath);
- return "$p[0]/MIME-types", $m;
+ my $m = pop;
+ $m =~ s#/#_#;
+ my @p = $ENV{CHOICESPATH}
+ ? split(/:/, $ENV{CHOICESPATH})
+ : (@choicespath);
+ return "$p[0]/MIME-types", $m;
}
1;
@@ -98,9 +99,9 @@ File::MimeInfo::Rox - Open files by mimetype "Rox style"
# more verbose version
my $mt = mimetype($somefile)
- || die "Could not find mimetype for $somefile\n";
+ || die "Could not find mimetype for $somefile\n";
mime_system($somefile, $mt)
- || die "No program to open $somefile available\n";
+ || die "No program to open $somefile available\n";
=head1 DESCRIPTION
diff --git a/mimeopen b/mimeopen
index 4822a52..33ed359 100755
--- a/mimeopen
+++ b/mimeopen
@@ -1,71 +1,75 @@
#!/usr/bin/perl
use strict;
-our $VERSION = '0.29';
+use warnings;
+our $VERSION = '0.30';
$|++;
# ########## #
# Parse ARGV #
# ########## #
+use Encode::Locale;
+use Encode;
+@ARGV = map { decode(locale => $_, 1) } @ARGV;
+
my %args = ();
my %opts = (
- # name => [char, expect_arg_bit ]
- 'help' => ['h'],
- 'usage' => ['u'],
- 'version' => ['v'],
- 'stdin' => [''],
- 'dereference' => ['L'],
- 'debug' => ['D'],
- 'database' => ['', 1],
- 'magic-only' => ['M'],
- 'ask' => ['a'],
- 'ask-default' => ['d'],
- 'no-ask' => ['n'],
+ 'help' => ['h'],
+ 'usage' => ['u'],
+ 'version' => ['v'],
+ 'stdin' => [''],
+ 'dereference' => ['L'],
+ 'debug' => ['D'],
+ 'database' => ['', 1],
+ 'magic-only' => ['M'],
+ 'ask' => ['a'],
+ 'ask-default' => ['d'],
+ 'no-ask' => ['n'],
);
while ((@ARGV) && ($ARGV[0] =~ /^-/)) {
- my $opt = shift @ARGV;
- if ($opt =~ /^--?$/) {
- last;
- }
- elsif ($opt =~ s/^--([\w-]+)(?:=(.*))?/$1/) {
- if (exists $opts{$opt}) {
- if ($opts{$opt}[1]) {
- my $arg = $2 || shift @ARGV;
- complain('--'.$opt, 2) unless defined $arg;
- $args{$opt} .= ( $args{$opt} ? ' ' : '' ) . $arg;
- }
- else { $args{$opt}++ }
- }
- else { complain('--'.$opt) }
- }
- elsif ($opt =~ s/^-(?!-)//) {
- foreach my $o (split //, $opt) {
- my ($key) = grep { $opts{$_}[0] eq $o } keys %opts;
- complain($o) unless $key;
-
- if ($opts{$key}[1]) {
- my $arg = shift @ARGV;
- complain('-'.$o, 2) unless defined $arg;
- $args{$key} .= ( $args{$key} ? ' ' : '' ).$arg; # join with whitespace
- }
- else { $args{$key}++; }
- }
- }
- else { complain($opt) }
+ my $opt = shift @ARGV;
+ if ($opt =~ /^--?$/) {
+ last;
+ }
+ elsif ($opt =~ s/^--([\w-]+)(?:=(.*))?/$1/) {
+ if (exists $opts{$opt}) {
+ if ($opts{$opt}[1]) {
+ my $arg = $2 || shift @ARGV;
+ complain('--'.$opt, 2) unless defined $arg;
+ $args{$opt} .= ( $args{$opt} ? ' ' : '' ) . $arg;
+ }
+ else { $args{$opt}++ }
+ }
+ else { complain('--'.$opt) }
+ }
+ elsif ($opt =~ s/^-(?!-)//) {
+ foreach my $o (split //, $opt) {
+ my ($key) = grep { $opts{$_}[0] eq $o } keys %opts;
+ complain($o) unless $key;
+
+ if ($opts{$key}[1]) {
+ my $arg = shift @ARGV;
+ complain('-'.$o, 2) unless defined $arg;
+ $args{$key} .= ( $args{$key} ? ' ' : '' ).$arg; # join with whitespace
+ }
+ else { $args{$key}++; }
+ }
+ }
+ else { complain($opt) }
}
if ($args{help} || $args{usage}) {
- eval 'use Pod::Usage';
- die "Could not find perl module Pod::Usage\n" if $@;
- pod2usage( {
- -verbose => 1,
- -exitval => 0,
- } );
+ eval 'use Pod::Usage';
+ die "Could not find perl module Pod::Usage\n" if $@;
+ pod2usage( {
+ -verbose => 1,
+ -exitval => 0,
+ } );
}
if ($args{version}) {
- print "mimeopen $VERSION\n\n", << 'EOV';
+ print "mimeopen $VERSION\n\n", << 'EOV';
Copyright (c) 2005, 2012 Jaap G Karssenberg. All rights reserved.
This program is free software; you can redistribute it and/or
modify it under the same terms as Perl.
@@ -74,7 +78,7 @@ 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.
EOV
- exit 0;
+ exit 0;
}
complain(undef, 4) unless scalar(@ARGV);
@@ -84,7 +88,10 @@ complain(undef, 4) unless scalar(@ARGV);
# ############# #
# --database
-@File::MimeInfo::DIRS = split /:/, $args{database} if $args{database};
+{
+ no warnings 'once';
+ @File::MimeInfo::DIRS = split /:/, $args{database} if $args{database};
+}
## Actually use our modules ##
eval 'use File::MimeInfo::Magic qw/mimetype magic/;';
@@ -92,27 +99,35 @@ die $@ if $@;
eval 'use File::MimeInfo::Applications;';
die $@ if $@;
+
*default = \&File::MimeInfo::default;
# --debug
if ($args{debug}) {
- $File::MimeInfo::DEBUG++;
- $File::MimeInfo::Magic::DEBUG++;
- print '> Data dirs are: ', join( ', ',
- $args{database}
- ? ( split /:/, $args{database} )
- : (
- File::BaseDir::xdg_data_home(),
- File::BaseDir::xdg_data_dirs()
- )
- ), "\n";
+ {
+ no warnings 'once';
+ $File::MimeInfo::DEBUG++;
+ $File::MimeInfo::Magic::DEBUG++;
+ }
+ print '> Data dirs are: ', join( ', ',
+ $args{database}
+ ? ( split /:/, $args{database} )
+ : (
+ File::BaseDir::xdg_data_home(),
+ File::BaseDir::xdg_data_dirs()
+ )
+ ), "\n";
}
# --dereference ## deprecated - so always true
$args{dereference} = 1;
if ($args{dereference}) {
- eval 'use File::Spec';
- die "Could not find perl module File::Spec\n" if $@;
+ eval 'use File::Spec';
+ die "Could not find perl module File::Spec\n" if $@;
+}
+
+if (!File::MimeInfo::has_mimeinfo_database()) {
+ die "No mimeinfo database found\n";
}
# ######## #
@@ -126,46 +141,45 @@ my $file = $ARGV[0];
my $f = ($args{dereference} && -l $file) ? resolvelink($file) : $file;
# --magic-only
$mimetype = $args{'magic-only'}
- ? (magic($f) || default($f))
- : mimetype($f) ;
+ ? (magic($f) || default($f))
+ : mimetype($f) ;
unless (length $mimetype) {
- print STDERR "Could not determine mimetype for file: $file\n";
- exit 5;
+ print STDERR "Could not determine mimetype for file: $file\n";
+ exit 5;
}
my ($default, @other) = mime_applications_all($mimetype);
-## Removed this because user should always be able to select "Other..."
-#unless($default or @other) {
-# print STDERR "No applications found for mimetype: $mimetype\n";
-# exit 6;
-#}
-##
-
if ($args{'no-ask'}) {
- $default = defined($default) ? $default : $other[0];
+ $default = defined($default) ? $default : $other[0];
}
elsif ($args{'ask'}) {
- $default = choose($mimetype, 0, grep defined($_), $default, @other);
+ $default = choose($mimetype, 0, grep defined($_), $default, @other);
}
elsif ($args{'ask-default'}) {
- $default = choose($mimetype, 1, grep defined($_), $default, @other);
+ $default = choose($mimetype, 1, grep defined($_), $default, @other);
}
elsif (! defined $default) {
- ($default) = (@other == 1) ? (@other) : choose($mimetype, 1, @other);
+ ($default) = (@other == 1) ? (@other) : choose($mimetype, 1, @other);
+}
+
+unless($default) {
+ # $default can still be undef, if $other[0] is undef and no-ask is set.
+ print STDERR "No applications found for mimetype: $mimetype\n.";
+ exit 6;
}
print 'Opening '.join(', ', map qq{"$_"}, @ARGV)
- . ' with '.$default->get_value('Name')." ($mimetype)\n";
+ . ' with '.$default->get_value('Name')." ($mimetype)\n";
#print STDERR "exec string: ".$default->parse_Exec(@ARGV)."\n";
if (@ARGV == 1 or $default->wants_list) {
- $default->exec(@ARGV);
+ $default->exec(@ARGV);
}
else {
- my $last = pop @ARGV;
- fork or $default->exec($_) for @ARGV;
- $default->exec($last);
+ my $last = pop @ARGV;
+ fork or $default->exec($_) for @ARGV;
+ $default->exec($last);
}
exit 7; # something went wrong in the exec
@@ -175,79 +189,79 @@ exit 7; # something went wrong in the exec
# ########### #
sub choose {
- my ($mime, $set_default, @app) = @_;
- print $set_default ?
- "Please choose a default application for files of type $mime\n\n" :
- "Please choose an application\n\n" ;
- my @done;
- for my $i (0 .. $#app) {
- my (undef, undef, $file) =
- File::Spec->splitpath( $app[$i]->{file} );
- $file =~ s/\.desktop$//;
- if (grep {$_ eq $file} @done) {
- $app[$i] = undef;
- }
- else {
- push @done, $file;
- print "\t", scalar(@done), ") ",
- $app[$i]->get_value('Name'), " ($file)\n";
- }
- }
- @app = grep defined($_), @app;
- print "\t", scalar(@done)+1, ") Other...\n" if $set_default;
- print "\nuse application #";
- my $c = <STDIN>;
- chomp $c;
-
- unless ($c =~ /^\d+$/) {
- print STDERR "Cancelled\n";
- exit 8;
- }
- $c--; # base-1 => base-0
-
- if ($set_default and $c == scalar(@done)) {
- # ask for custom command
- print "use command: ";
- my $cmd = <STDIN>;
- chomp $cmd;
- push @app,
- eval { mime_applications_set_custom($mime => $cmd) };
- warn $@ if $@;
- }
- elsif ($c > scalar(@app)) {
- print STDERR "Cancelled\n";
- exit 8;
- }
- elsif ($set_default) {
- eval { mime_applications_set_default($mime => $app[$c]) };
- warn $@ if $@;
- }
-
- return $app[$c];
+ my ($mime, $set_default, @app) = @_;
+ print $set_default ?
+ "Please choose a default application for files of type $mime\n\n" :
+ "Please choose an application\n\n" ;
+ my @done;
+ for my $i (0 .. $#app) {
+ my (undef, undef, $file) =
+ File::Spec->splitpath( $app[$i]->{file} );
+ $file =~ s/\.desktop$//;
+ if (grep {$_ eq $file} @done) {
+ $app[$i] = undef;
+ }
+ else {
+ push @done, $file;
+ print "\t", scalar(@done), ") ",
+ $app[$i]->get_value('Name'), " ($file)\n";
+ }
+ }
+ @app = grep defined($_), @app;
+ print "\t", scalar(@done)+1, ") Other...\n" if $set_default;
+ print "\nuse application #";
+ my $c = <STDIN>;
+ chomp $c;
+
+ unless ($c =~ /^\d+$/) {
+ print STDERR "Cancelled\n";
+ exit 8;
+ }
+ $c--; # base-1 => base-0
+
+ if ($set_default and $c == scalar(@done)) {
+ # ask for custom command
+ print "use command: ";
+ my $cmd = <STDIN>;
+ chomp $cmd;
+ push @app,
+ eval { mime_applications_set_custom($mime => $cmd) };
+ warn $@ if $@;
+ }
+ elsif ($c > scalar(@app)) {
+ print STDERR "Cancelled\n";
+ exit 8;
+ }
+ elsif ($set_default) {
+ eval { mime_applications_set_default($mime => $app[$c]) };
+ warn $@ if $@;
+ }
+
+ return $app[$c];
}
sub complain { # Error messages
- my $opt = shift;
- my $m = shift || 1;
-
- my $bn = $0;
- $bn =~ s|^(.*/)*||;
- if ($m == 1) { print STDERR "$bn: unrecognized option '$opt'" }
- elsif ($m == 2) { print STDERR "$bn: option '$opt' requires an argument" }
- elsif ($m == 3) { print STDERR "$bn: $opt: No such file or directory\n" }
- elsif ($m == 4) { print STDERR "usage: $bn [options] files" }
-
- print "\nTry '$bn --help' for more information.\n" unless $m == 3;
- exit $m;
+ my $opt = shift;
+ my $m = shift || 1;
+
+ my $bn = $0;
+ $bn =~ s|^(.*/)*||;
+ if ($m == 1) { print STDERR "$bn: unrecognized option '$opt'" }
+ elsif ($m == 2) { print STDERR "$bn: option '$opt' requires an argument" }
+ elsif ($m == 3) { print STDERR "$bn: $opt: No such file or directory\n" }
+ elsif ($m == 4) { print STDERR "usage: $bn [options] files" }
+
+ print "\nTry '$bn --help' for more information.\n" unless $m == 3;
+ exit $m;
}
sub resolvelink { # --dereference
- my $file = shift;
- my $link = readlink($file) || return $file;
- my (undef, $dir, undef) = File::Spec->splitpath($file);
- $link = File::Spec->rel2abs($link, $dir);
- $link = resolvelink($link) if -l $link; # recurs
- return $link;
+ my $file = shift;
+ my $link = readlink($file) || return $file;
+ my (undef, $dir, undef) = File::Spec->splitpath($file);
+ $link = File::Spec->rel2abs($link, $dir);
+ $link = resolvelink($link) if -l $link; # recurs
+ return $link;
}
__END__
diff --git a/mimetype b/mimetype
index a9edebf..c58ba9c 100755
--- a/mimetype
+++ b/mimetype
@@ -1,81 +1,85 @@
#!/usr/bin/perl
use strict;
-our $VERSION = '0.29';
+use warnings;
+our $VERSION = '0.30';
$|++;
# ########## #
# Parse ARGV #
# ########## #
+use Encode::Locale;
+use Encode;
+@ARGV = map { decode(locale => $_, 1) } @ARGV;
+
my %args = ();
my %opts = (
- # name => [char, expect_arg_bit ]
- 'help' => ['h'],
- 'usage' => ['u'],
- 'version' => ['v'],
- 'stdin' => [''],
- 'brief' => ['b'],
- 'namefile' => ['f', 1],
- 'noalign' => ['N'],
- 'describe' => ['d'],
- 'file-compat' => [''],
- 'output-format' => ['', 1],
- 'language' => ['l', 1],
- 'mimetype' => ['i'],
- 'dereference' => ['L'],
- 'separator' => ['F',1],
- 'debug' => ['D'],
- 'database' => ['', 1],
- 'all' => ['a'],
- 'magic-only' => ['M'],
+ 'help' => ['h'],
+ 'usage' => ['u'],
+ 'version' => ['v'],
+ 'stdin' => [''],
+ 'brief' => ['b'],
+ 'namefile' => ['f', 1],
+ 'noalign' => ['N'],
+ 'describe' => ['d'],
+ 'file-compat' => [''],
+ 'output-format' => ['', 1],
+ 'language' => ['l', 1],
+ 'mimetype' => ['i'],
+ 'dereference' => ['L'],
+ 'separator' => ['F',1],
+ 'debug' => ['D'],
+ 'database' => ['', 1],
+ 'all' => ['a'],
+ 'magic-only' => ['M'],
);
$args{'file-compat'}++ if $0 =~ m#(^|/)file$#;
while ((@ARGV) && ($ARGV[0] =~ /^-/)) {
- my $opt = shift @ARGV;
- if ($opt =~ /^--?$/) {
- $args{stdin}++ if $args{'file-compat'} && $opt eq '-';
- last;
- }
- elsif ($opt =~ s/^--([\w-]+)(?:=(.*))?/$1/) {
- if (exists $opts{$opt}) {
- if ($opts{$opt}[1]) {
- my $arg = $2 || shift @ARGV;
- complain('--'.$opt, 2) unless defined $arg;
- $args{$opt} .= ( $args{$opt} ? ' ' : '' ) . $arg;
- }
- else { $args{$opt}++ }
- }
- else { complain('--'.$opt) }
- }
- elsif ($opt =~ s/^-(?!-)//) {
- foreach my $o (split //, $opt) {
- my ($key) = grep { $opts{$_}[0] eq $o } keys %opts;
- complain($o) unless $key;
-
- if ($opts{$key}[1]) {
- my $arg = shift @ARGV;
- complain('-'.$o, 2) unless defined $arg;
- $args{$key} .= ( $args{$key} ? ' ' : '' ).$arg; # join with whitespace
- }
- else { $args{$key}++; }
- }
- }
- else { complain($opt) }
+ my $opt = shift @ARGV;
+ if ($opt =~ /^--?$/) {
+ $args{stdin}++ if $args{'file-compat'} && $opt eq '-';
+ last;
+ }
+ elsif ($opt =~ s/^--([\w-]+)(?:=(.*))?/$1/) {
+ if (exists $opts{$opt}) {
+ if ($opts{$opt}[1]) {
+ my $arg = $2 || shift @ARGV;
+ complain('--'.$opt, 2) unless defined $arg;
+ $args{$opt} .= ( $args{$opt} ? ' ' : '' ) . $arg;
+ }
+ else { $args{$opt}++ }
+ }
+ else { complain('--'.$opt) }
+ }
+ elsif ($opt =~ s/^-(?!-)//) {
+ foreach my $o (split //, $opt) {
+ my ($key) = grep { $opts{$_}[0] eq $o } keys %opts;
+ complain($o) unless $key;
+
+ if ($opts{$key}[1]) {
+ my $arg = shift @ARGV;
+ complain('-'.$o, 2) unless defined $arg;
+ $args{$key} .= ( $args{$key} ? ' ' : '' ).$arg; # join with whitespace
+ }
+ else { $args{$key}++; }
+ }
+ }
+ else { complain($opt) }
}
if ($args{help} || $args{usage}) {
- eval 'use Pod::Usage';
- die "Could not find perl module Pod::Usage\n" if $@;
- pod2usage( {
- -verbose => 1,
- -exitval => 0,
- } );
+ eval 'use Pod::Usage';
+ die "Could not find perl module Pod::Usage\n" if $@;
+ pod2usage( {
+ -verbose => 1,
+ -exitval => 0,
+ } );
}
if ($args{version}) {
- print "mimetype $VERSION\n\n", << 'EOV';
+ print "mimetype $VERSION\n\n", << 'EOV';
Copyright (c) 2003, 2012 Jaap G Karssenberg. All rights reserved.
This program is free software; you can redistribute it and/or
modify it under the same terms as Perl.
@@ -84,7 +88,7 @@ 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.
EOV
- exit 0;
+ exit 0;
}
complain(undef, 4) unless scalar(@ARGV) || $args{stdin} || $args{namefile};
@@ -96,7 +100,10 @@ complain(undef, 4) unless scalar(@ARGV) || $args{stdin} || $args{namefile};
our %desc; # desc caching hash
# --database
-@File::MimeInfo::DIRS = split /:/, $args{database} if $args{database};
+{
+ no warnings 'once';
+ @File::MimeInfo::DIRS = split /:/, $args{database} if $args{database};
+}
## Actually use our module ##
eval 'use File::MimeInfo::Magic qw/mimetype globs inodetype magic describe/;';
@@ -106,16 +113,19 @@ die $@ if $@;
# --debug
if ($args{debug}) {
- $File::MimeInfo::DEBUG++;
- $File::MimeInfo::Magic::DEBUG++;
- print '> Data dirs are: ', join( ', ',
- $args{database}
- ? ( split /:/, $args{database} )
- : (
- File::BaseDir::xdg_data_home(),
- File::BaseDir::xdg_data_dirs()
- )
- ), "\n";
+ {
+ no warnings 'once';
+ $File::MimeInfo::DEBUG++;
+ $File::MimeInfo::Magic::DEBUG++;
+ }
+ print '> Data dirs are: ', join( ', ',
+ $args{database}
+ ? ( split /:/, $args{database} )
+ : (
+ File::BaseDir::xdg_data_home(),
+ File::BaseDir::xdg_data_dirs()
+ )
+ ), "\n";
}
# --file-compat
@@ -123,40 +133,47 @@ $args{describe}++ if $args{'file-compat'} && !$args{mimetype};
# --namefile
if ($args{namefile}) {
- open IN, $args{namefile}
- || die "Couldn't open file: $args{namefile}\n";
- unshift @ARGV, map {chomp; $_} (<IN>);
- close IN;
+ open IN, $args{namefile}
+ || die "Couldn't open file: $args{namefile}\n";
+ unshift @ARGV, map {chomp; $_} (<IN>);
+ close IN;
}
# --language
-$File::MimeInfo::LANG = $args{language} if $args{language};
+{
+ no warnings 'once';
+ $File::MimeInfo::LANG = $args{language} if $args{language};
+}
# Formatting stuff
my $l = 5; # "STDIN"
unless ($args{brief} || $args{noalign}) {
- for (@ARGV) { $l = length($_) if $l < length($_) }
+ for (@ARGV) { $l = length($_) if $l < length($_) }
}
$args{separator} = ':' unless defined $args{separator};
my $format = $args{'output-format'}
- ? parse_format($args{'output-format'})
- : $args{brief}
- ? sub { $args{describe} ? desc($_[1]) : $_[1] }
- : $args{noalign}
- ? sub { ( $_[0], $args{separator}, ' ', $args{describe} ? desc($_[1]) : $_[1] ) }
- : sub { ( $_[0], $args{separator}, ' 'x($l + 1 - length($_[0])),
- $args{describe} ? desc($_[1]) : $_[1] ) };
+ ? parse_format($args{'output-format'})
+ : $args{brief}
+ ? sub { $args{describe} ? desc($_[1]) : $_[1] }
+ : $args{noalign}
+ ? sub { ( $_[0], $args{separator}, ' ', $args{describe} ? desc($_[1]) : $_[1] ) }
+ : sub { ( $_[0], $args{separator}, ' 'x($l + 1 - length($_[0])),
+ $args{describe} ? desc($_[1]) : $_[1] ) };
# --dereference
if ($args{dereference}) {
- eval 'use File::Spec';
- die "Could not find perl module File::Spec\n" if $@;
+ eval 'use File::Spec';
+ die "Could not find perl module File::Spec\n" if $@;
}
# --stdin
if ($args{stdin}) {
- eval 'use IO::Scalar';
- die "Could not find perl module IO::Scalar\n" if $@;
+ eval 'use IO::Scalar';
+ die "Could not find perl module IO::Scalar\n" if $@;
+}
+
+if (!File::MimeInfo::has_mimeinfo_database()) {
+ die "No mimeinfo database found\n";
}
# ######## #
@@ -165,28 +182,33 @@ if ($args{stdin}) {
# --stdin
if ($args{stdin}) {
- my $data;
- read(STDIN, $data, $File::MimeInfo::Magic::max_buffer);
- my $scalar = new IO::Scalar \$data;
- print $format->('STDIN', mimetype($scalar)), "\n";
- exit;
+ my $data;
+ {
+ no warnings 'once';
+ read(STDIN, $data, $File::MimeInfo::Magic::max_buffer);
+ }
+ my $scalar = new IO::Scalar \$data;
+ print $format->('STDIN', mimetype($scalar)), "\n";
+ exit;
}
foreach my $file (@ARGV) {
- # --dereference
- my $f = ($args{dereference} && -l $file) ? resolvelink($file) : $file;
- # --magic-only
- if ($args{'magic-only'}) {
- print $format->($file, magic($f) || default($f)), "\n";
- }
- # --all
- elsif ($args{all}) {
- for (qw#inodetype globs magic default#) {
- my $m = eval "$_(\$f)";
- print $format->($file, $m), "\n" if $m;
- }
- }
- else { print $format->($file, mimetype($f)), "\n" }
+ # --dereference
+ my $f = ($args{dereference} && -l $file) ? resolvelink($file) : $file;
+ # --magic-only
+ if ($args{'magic-only'}) {
+ print $format->($file, magic($f) || default($f)), "\n";
+ }
+ # --all
+ elsif ($args{all}) {
+ for (qw#inodetype globs magic default#) {
+ my $m = eval "$_(\$f)";
+ print $format->($file, $m), "\n" if $m;
+ }
+ }
+ else {
+ print $format->($file, mimetype($f)), "\n"
+ }
}
exit;
@@ -196,43 +218,43 @@ exit;
# ########### #
sub complain { # Error messages
- my $opt = shift;
- my $m = shift || 1;
-
- my $bn = $0;
- $bn =~ s|^(.*/)*||;
- if ($m == 1) { print STDERR "$bn: unrecognized option '$opt'" }
- elsif ($m == 2) { print STDERR "$bn: option '$opt' requires an argument" }
- elsif ($m == 3) { print STDERR "$bn: $opt: No such file or directory\n" }
- elsif ($m == 4) { print STDERR "usage: $bn [options] files" }
-
- print "\nTry '$bn --help' for more information.\n" unless $m == 3;
- exit $m;
+ my $opt = shift;
+ my $m = shift || 1;
+
+ my $bn = $0;
+ $bn =~ s|^(.*/)*||;
+ if ($m == 1) { print STDERR "$bn: unrecognized option '$opt'" }
+ elsif ($m == 2) { print STDERR "$bn: option '$opt' requires an argument" }
+ elsif ($m == 3) { print STDERR "$bn: $opt: No such file or directory\n" }
+ elsif ($m == 4) { print STDERR "usage: $bn [options] files" }
+
+ print "\nTry '$bn --help' for more information.\n" unless $m == 3;
+ exit $m;
}
sub parse_format { # Advanced formatting
- my $form = shift;
- my $code = "sub { '$form' }";
- # code will get @_ = qw/file type/
- $code =~ s/(?<!\\)%f/'.\$_[0].'/g;
- $code =~ s/(?<!\\)%m/'.\$_[1].'/g;
- $code =~ s/(?<!\\)%d/'.desc(\$_[1]).'/g;
- return eval $code;
+ my $form = shift;
+ my $code = "sub { '$form' }";
+ # code will get @_ = qw/file type/
+ $code =~ s/(?<!\\)%f/'.\$_[0].'/g;
+ $code =~ s/(?<!\\)%m/'.\$_[1].'/g;
+ $code =~ s/(?<!\\)%d/'.desc(\$_[1]).'/g;
+ return eval $code;
}
sub resolvelink { # --dereference
- my $file = shift;
- my $link = readlink($file) || return $file;
- my (undef, $dir, undef) = File::Spec->splitpath($file);
- $link = File::Spec->rel2abs($link, $dir);
- $link = resolvelink($link) if -l $link; # recurs
- return $link;
+ my $file = shift;
+ my $link = readlink($file) || return $file;
+ my (undef, $dir, undef) = File::Spec->splitpath($file);
+ $link = File::Spec->rel2abs($link, $dir);
+ $link = resolvelink($link) if -l $link; # recurs
+ return $link;
}
sub desc { # Cache description
- my $mt = shift;
- return undef unless $mt;
- $desc{$mt} ||= describe($mt) || describe($mt, ''); # second form overrules the language settings to default
+ my $mt = shift;
+ return undef unless $mt;
+ $desc{$mt} ||= describe($mt) || describe($mt, ''); # second form overrules the language settings to default
}
__END__
@@ -348,9 +370,9 @@ Do not align output fields.
If you want an alternative output format, you can specify a format string
containing the following escapes:
- %f for the filename
- %d description
- %m mime type
+ %f for the filename
+ %d description
+ %m mime type
Alignment is not available when using this,
you need to post-process the output to do that.
@@ -382,9 +404,9 @@ mime-info will be expected in the "mime" sub directory of one of these
directories. If these are not set, there will be searched for the
following directories:
- $HOME/.local/share/mime
- /usr/local/share/mime
- /usr/share/mime
+ $HOME/.local/share/mime
+ /usr/local/share/mime
+ /usr/share/mime
See also the "XDG Base Directory Specification"
L<http://freedesktop.org/Standards/basedir-spec>
diff --git a/t/000-report-versions-tiny.t b/t/000-report-versions-tiny.t
index 12a836a..34c41b9 100644
--- a/t/000-report-versions-tiny.t
+++ b/t/000-report-versions-tiny.t
@@ -49,13 +49,14 @@ sub pmver {
}
eval { $v .= pmver('Carp','any version') };
+eval { $v .= pmver('Encode::Locale','any version') };
eval { $v .= pmver('Exporter','any version') };
eval { $v .= pmver('Fcntl','any version') };
-eval { $v .= pmver('Pod::Usage','any version') };
eval { $v .= pmver('File::Spec','0.03') };
eval { $v .= pmver('File::DesktopEntry','0.04') };
-eval { $v .= pmver('Test::More','0.88') };
eval { $v .= pmver('Path::Tiny','any version') };
+eval { $v .= pmver('Pod::Usage','any version') };
+eval { $v .= pmver('Test::More','0.88') };
# All done.
diff --git a/t/00_use_ok.t b/t/00_use_ok.t
index 776c019..6737b2e 100644
--- a/t/00_use_ok.t
+++ b/t/00_use_ok.t
@@ -3,7 +3,7 @@ require_ok('File::MimeInfo');
require_ok('File::MimeInfo::Magic');
require_ok('File::MimeInfo::Rox');
SKIP: {
- eval "use File::DesktopEntry";
- skip('File::DesktopEntry not installed', 1) if $@;
- require_ok('File::MimeInfo::Applications');
+ eval "use File::DesktopEntry";
+ skip('File::DesktopEntry not installed', 1) if $@;
+ require_ok('File::MimeInfo::Applications');
}
diff --git a/t/01_normal.t b/t/01_normal.t
index 9139b18..45f398e 100644
--- a/t/01_normal.t
+++ b/t/01_normal.t
@@ -1,28 +1,28 @@
-
use strict;
+use warnings;
-use Test::More tests => 31;
+use Test::More;
$ENV{XDG_DATA_HOME} = './t/';
$ENV{XDG_DATA_DIRS} = './t/'; # forceing non default value
-use_ok('File::MimeInfo', qw/mimetype describe globs/); # 1
+use_ok('File::MimeInfo', qw/mimetype describe globs/);
# test what was read
+File::MimeInfo::rehash();
{
- no warnings; # don't bug me because I use these vars only once
- File::MimeInfo::rehash();
- ok(scalar(keys %File::MimeInfo::literal) == 1, 'literal data is there'); # 2
- ok(scalar(@File::MimeInfo::globs) == 1, 'globs data is there'); # 3
+ no warnings 'once';
+ ok(scalar(keys %File::MimeInfo::literal) == 1, 'literal data is there');
+ ok(scalar(@File::MimeInfo::globs) == 1, 'globs data is there');
}
# test _glob_to_regexp
my $i = 0;
for my $glob (
- [ '*.pl', [ '(?-xism:^.*\.pl$)', '(?^u:^.*\.pl$)', '(?^:^.*\.pl$)' ] ], # 4
- [ '*.h++', [ '(?-xism:^.*\.h\+\+$)', '(?^u:^.*\.h\+\+$)', '(?^:^.*\.h\+\+$)' ] ], # 5
- [ '*.[tar].*', [ '(?-xism:^.*\.[tar]\..*$)', '(?^u:^.*\.[tar]\..*$)', '(?^:^.*\.[tar]\..*$)' ] ], # 6
- [ '*.?', [ '(?-xism:^.*\..?$)', '(?^u:^.*\..?$)', '(?^:^.*\..?$)' ] ], # 7
+ [ '*.pl', [ '(?-xism:^.*\.pl$)', '(?^u:^.*\.pl$)', '(?^:^.*\.pl$)' ] ],
+ [ '*.h++', [ '(?-xism:^.*\.h\+\+$)', '(?^u:^.*\.h\+\+$)', '(?^:^.*\.h\+\+$)' ] ],
+ [ '*.[tar].*', [ '(?-xism:^.*\.[tar]\..*$)', '(?^u:^.*\.[tar]\..*$)', '(?^:^.*\.[tar]\..*$)' ] ],
+ [ '*.?', [ '(?-xism:^.*\..?$)', '(?^u:^.*\..?$)', '(?^:^.*\..?$)' ] ],
)
{
my $converted = File::MimeInfo::_glob_to_regexp( $glob->[0] );
@@ -39,50 +39,52 @@ for my $glob (
# test parsing file names
$i = 0;
for (
- ['script.pl', 'application/x-perl'], # 8
- ['script.old.pl', 'application/x-perl'], # 9
- ['script.PL', 'application/x-perl'], # 10 - case insensitive use of glob
- ['script.tar.pl', 'application/x-perl'], # 11
- ['script.gz', 'application/x-gzip'], # 12
- ['script.tar.gz', 'application/x-compressed-tar'], # 13
- ['INSTALL', 'text/x-install'], # 14
- ['script.foo.bar.gz', 'application/x-gzip'], # 15
- ['script.foo.tar.gz', 'application/x-compressed-tar'], # 16
- ['makefile', 'text/x-makefile'], # 17
- ['./makefile', 'text/x-makefile'], # 18
+ ['script.pl', 'application/x-perl'],
+ ['script.old.pl', 'application/x-perl'],
+ ['script.PL', 'application/x-perl'],
+ ['script.tar.pl', 'application/x-perl'],
+ ['script.gz', 'application/x-gzip'],
+ ['script.tar.gz', 'application/x-compressed-tar'],
+ ['INSTALL', 'text/x-install'],
+ ['script.foo.bar.gz', 'application/x-gzip'],
+ ['script.foo.tar.gz', 'application/x-compressed-tar'],
+ ['makefile', 'text/x-makefile'],
+ ['./makefile', 'text/x-makefile'],
) { is( mimetype($_->[0]), $_->[1], 'file '.++$i ) }
# test OO interface
my $ref = File::MimeInfo->new ;
-is(ref($ref), q/File::MimeInfo/, 'constructor works'); # 19
-is( $ref->mimetype('script.pl'), 'application/x-perl', 'OO syntax works'); # 20
+is(ref($ref), q/File::MimeInfo/, 'constructor works');
+is( $ref->mimetype('script.pl'), 'application/x-perl', 'OO syntax works');
# test default
-is( mimetype('t/default/binary_file'), 'application/octet-stream', 'default works for binary data'); # 21
-is( mimetype('t/default/plain_text'), 'text/plain', 'default works for plain text'); # 22
-is( mimetype('t/default/empty_file'), 'text/plain', 'default works for empty file'); # 23
-ok( ! defined mimetype('t/non_existing_file'), 'default works for non existing file'); # 24
-is( mimetype('t/default/utf8_text'), 'text/plain', 'we speak utf8' ); # 25
-is( mimetype('t/default/encoding_breakage'), 'application/octet-stream', 'encoding bug gone' ); # 26
+is( mimetype('t/default/binary_file'), 'application/octet-stream', 'default works for binary data');
+is( mimetype('t/default/plain_text'), 'text/plain', 'default works for plain text');
+is( mimetype('t/default/empty_file'), 'text/plain', 'default works for empty file');
+ok( ! defined mimetype('t/non_existing_file'), 'default works for non existing file');
+is( mimetype('t/default/utf8_text'), 'text/plain', 'we speak utf8' );
+is( mimetype('t/default/encoding_breakage'), 'application/octet-stream', 'encoding bug gone' );
# test inode thingy
-is( mimetype('t'), 'inode/directory', 'directories are recognized'); # 27
+is( mimetype('t'), 'inode/directory', 'directories are recognized');
SKIP: {
- unlink 't/symlink' or die "Could not unlink t/symlink"
- if -l 't/symlink';
- skip('symlink not supported', 1)
- unless eval { symlink("",""); 1 }
- and symlink('t/default' => 't/symlink') ;
- is( mimetype('t/symlink'), 'inode/symlink', 'symlinks are recognized'); # 28
+ unlink 't/symlink' or die "Could not unlink t/symlink"
+ if -l 't/symlink';
+ skip('symlink not supported', 1)
+ unless eval { symlink("",""); 1 }
+ and symlink('t/default' => 't/symlink') ;
+ is( mimetype('t/symlink'), 'inode/symlink', 'symlinks are recognized');
}
# test describe
-ok( describe('text/plain') eq 'Plain Text', 'describe works' ); # 29
+ok( describe('text/plain') eq 'Plain Text', 'describe works' );
{
- no warnings; # don't bug me because I use this var only once
- $File::MimeInfo::LANG = 'nl';
+ no warnings 'once';
+ $File::MimeInfo::LANG = 'nl';
+ ok( describe('text/plain') eq 'Platte tekst', 'describe works with other languages' );
}
-ok( describe('text/plain') eq 'Platte tekst', 'describe works with other languages' ); # 30
-is( mimetype('t/test.png'), 'image/png', 'glob priority observed'); # 31
+is( mimetype('t/test.png'), 'image/png', 'glob priority observed');
+
+done_testing;
diff --git a/t/02_magic.t b/t/02_magic.t
index 5108d97..dbadf08 100644
--- a/t/02_magic.t
+++ b/t/02_magic.t
@@ -13,10 +13,10 @@ Test::More->import( tests => (2 * scalar(@files) + 1) );
use_ok('File::MimeInfo::Magic', qw/mimetype magic/);
for (@files) {
- $type = $_;
- $type =~ tr#_#/#;
- $type =~ s#\.\w+$##;
- ok( mimetype("t/magic/$_") eq $type, "complete (magic) typing of $_");
- undef $type if $type eq "text/plain" || $type eq "application/octet-stream";
- ok( magic("t/magic/$_") eq $type, "magic typing of $_" );
+ $type = $_;
+ $type =~ tr#_#/#;
+ $type =~ s#\.\w+$##;
+ ok( mimetype("t/magic/$_") eq $type, "complete (magic) typing of $_");
+ undef $type if $type eq "text/plain" || $type eq "application/octet-stream";
+ ok( magic("t/magic/$_") eq $type, "magic typing of $_" );
}
diff --git a/t/03_rox.t b/t/03_rox.t
index cafa4a4..af9089d 100644
--- a/t/03_rox.t
+++ b/t/03_rox.t
@@ -1,5 +1,7 @@
+use strict;
+use warnings;
-use Test::More tests => 2;
+use Test::More;
$ENV{XDG_DATA_HOME} = './t/';
$ENV{XDG_DATA_DIRS} = './t/'; # forceing non default value
@@ -9,9 +11,9 @@ $ENV{CHOICESPATH} = './t';
use_ok(q/File::MimeInfo::Rox/);
is_deeply(
- [File::MimeInfo::Rox::suggest_script_name('video/mpeg')],
- ['./t/MIME-types', 'video_mpeg'],
- 'suggest_script_name works' );
+ [File::MimeInfo::Rox::suggest_script_name('video/mpeg')],
+ ['./t/MIME-types', 'video_mpeg'],
+ 'suggest_script_name works' );
# dunno what more to test :S
-
+done_testing;
diff --git a/t/04_IO_objects.t b/t/04_IO_objects.t
index 51fac45..d579121 100644
--- a/t/04_IO_objects.t
+++ b/t/04_IO_objects.t
@@ -1,5 +1,6 @@
use strict;
-require Test::More;
+use warnings;
+use Test::More;
$ENV{XDG_DATA_HOME} = './t/';
$ENV{XDG_DATA_DIRS} = './t/'; # forceing non default value
@@ -14,20 +15,20 @@ eval "use File::MimeInfo::Magic"; # force runtime evaluation
die $@ if $@;
unless (eval 'require IO::Scalar') {
- ok(1, 'Skip - no IO::Scalar found') for 0 .. $#files;
+ ok(1, 'Skip - no IO::Scalar found') for 0 .. $#files;
}
else {
- for (@files) {
- my $type = $_;
- $type =~ tr#_#/#;
+ for (@files) {
+ my $type = $_;
+ $type =~ tr#_#/#;
- open FILE, "t/magic/$_" || die $!;
- my $file = join '', (<FILE>);
- close FILE;
- my $io = new IO::Scalar \$file;
+ open FILE, "t/magic/$_" || die $!;
+ my $file = join '', (<FILE>);
+ close FILE;
+ my $io = new IO::Scalar \$file;
- ok( mimetype($io) eq $type, "typing of $_ as io::scalar" )
- }
+ ok( mimetype($io) eq $type, "typing of $_ as io::scalar" )
+ }
}
__END__
@@ -35,11 +36,10 @@ __END__
# Not all platforms seem to support <:encoding(latin2) :(
unless (eval 'require IO::File') {
- ok(1, 'Skip - no IO::File found');
- exit 0;
+ ok(1, 'Skip - no IO::File found');
+ exit 0;
}
my $io = new IO::File;
$io->open('t/text_plain_czech', '<:encoding(latin2)');
ok( mimetype($io) eq 'text/plain', "czech (ISO 8859-2) encoded text" );
-
diff --git a/t/05_more.t b/t/05_more.t
index d77187b..f57b2ef 100644
--- a/t/05_more.t
+++ b/t/05_more.t
@@ -1,62 +1,63 @@
use strict;
+use warnings;
use File::Spec;
-use Test::More tests => 16;
+use Test::More;
$ENV{XDG_DATA_HOME} = './t/';
$ENV{XDG_DATA_DIRS} = './t/'; # forceing non default value
-use_ok('File::MimeInfo', qw/extensions mimetype_canon mimetype_isa/); # 1
+use_ok('File::MimeInfo', qw/extensions mimetype_canon mimetype_isa/);
## test reverse extension lookup
-ok( extensions('text/plain') eq 'asc', 'extenions works'); # 2
-is_deeply( [extensions('text/plain')], [qw#asc txt#], 'wantarray extensions works' ); # 3
+ok( extensions('text/plain') eq 'asc', 'extenions works');
+is_deeply( [extensions('text/plain')], [qw#asc txt#], 'wantarray extensions works' );
+# call above should have triggered rehash()
{
- # call above should have triggered rehash()
- no warnings; # don't bug me because I use these vars only once
- is(scalar(keys %File::MimeInfo::extension), 7, 'extension data is there'); # 4
+ no warnings 'once';
+ is(scalar(keys %File::MimeInfo::extension), 7, 'extension data is there');
}
## test alias lookup
-ok(mimetype_canon('text/plain') eq 'text/plain', 'canon is transparent'); # 5
-ok(mimetype_canon('application/x-pdf') eq 'application/pdf', 'canon works'); # 6
+ok(mimetype_canon('text/plain') eq 'text/plain', 'canon is transparent');
+ok(mimetype_canon('application/x-pdf') eq 'application/pdf', 'canon works');
## test subclass lookup
-ok(mimetype_isa('text/foo', 'text/plain'), 'implicite text/plain subclass'); # 7
-is_deeply([mimetype_isa('text/foo')], [qw(text/plain application/octet-stream)], 'implite application/octet-stream subclass'); # 8
-ok(mimetype_isa('inode/mount-point', 'inode/directory'), 'implicte inode/directory subclass'); # 9
-ok(mimetype_isa('application/x-perl', 'application/x-executable'), 'subclass form file'); # 10
-is_deeply([mimetype_isa('application/x-perl')], [qw(application/x-executable text/plain application/octet-stream)], 'subclass list from file'); # 11
+ok(mimetype_isa('text/foo', 'text/plain'), 'implicite text/plain subclass');
+is_deeply([mimetype_isa('text/foo')], [qw(text/plain application/octet-stream)], 'implite application/octet-stream subclass');
+ok(mimetype_isa('inode/mount-point', 'inode/directory'), 'implicte inode/directory subclass');
+ok(mimetype_isa('application/x-perl', 'application/x-executable'), 'subclass form file');
+is_deeply([mimetype_isa('application/x-perl')], [qw(application/x-executable text/plain application/octet-stream)], 'subclass list from file');
## Tests for Applications
SKIP: {
- eval { require File::DesktopEntry };
- skip "File::DesktopEntry not installed", 3 if $@;
-
- use_ok('File::MimeInfo::Applications');
-
-
- my %list = (
- 'text/plain' => 'foo.desktop',
- 'image/svg+xml' => 'mirage.desktop',
- );
-
- for my $type (keys %list) {
-
- my ($default, @other) = mime_applications($type);
- ok (
- !defined($default) &&
- (@other == 1) &&
- ref($other[0]) eq 'File::DesktopEntry',
- 'mime_application() works'
- );
- is (
- $other[0]->{file},
- File::Spec->catfile('t', 'applications', $list{$type}),
- "desktop file is the right one",
- );
- }
+ eval { require File::DesktopEntry };
+ skip "File::DesktopEntry not installed", 3 if $@;
+
+ use_ok('File::MimeInfo::Applications');
+
+
+ my %list = (
+ 'text/plain' => 'foo.desktop',
+ 'image/svg+xml' => 'mirage.desktop',
+ );
+
+ for my $type (keys %list) {
+
+ my ($default, @other) = mime_applications($type);
+ ok (
+ !defined($default) &&
+ (@other == 1) &&
+ ref($other[0]) eq 'File::DesktopEntry',
+ 'mime_application() works'
+ );
+ is (
+ $other[0]->{file},
+ File::Spec->catfile('t', 'applications', $list{$type}),
+ "desktop file is the right one",
+ );
+ }
}
-
+done_testing;
diff --git a/t/06_pod_ok.t b/t/06_pod_ok.t
index 091e399..ff44267 100644
--- a/t/06_pod_ok.t
+++ b/t/06_pod_ok.t
@@ -1,4 +1,4 @@
use Test::More;
eval "use Test::Pod 1.00";
plan skip_all => "Test::Pod 1.00 required for testing POD" if $@;
-all_pod_files_ok( all_pod_files(qw/bin lib/) );
+all_pod_files_ok( all_pod_files(qw/mimeopen mimetype lib/) );
diff --git a/t/10filehandle.t b/t/10filehandle.t
index 92ad2a9..8862159 100644
--- a/t/10filehandle.t
+++ b/t/10filehandle.t
@@ -9,6 +9,10 @@ if ($@) {
plan skip_all => "module Path::Tiny not installed \n";
}
+if (!File::MimeInfo::has_mimeinfo_database()) {
+ plan skip_all => "No mimeinfo database found \n";
+}
+
is(mimetype(path('test.png')), 'image/png', 'mimetype of test.png');
is(mimetype(path('../t/test.png')), 'image/png', 'mimetype of file with path');
is(inodetype(path('test.png')), undef, 'inodetype of test.png');
diff --git a/t/11mimeinfo.t b/t/11mimeinfo.t
index f8b4c98..01a19ea 100644
--- a/t/11mimeinfo.t
+++ b/t/11mimeinfo.t
@@ -2,13 +2,20 @@ use strict;
use warnings;
use Test::More;
-
+use File::MimeInfo;
use File::Spec;
+use File::Temp;
use FindBin qw($Bin);
eval "use IO::Scalar";
my $have_io_scalar = !$@;
+if (!File::MimeInfo::has_mimeinfo_database()) {
+ plan skip_all => "No mimeinfo database found \n";
+}
+
+my $empty_dir = File::Temp::tempdir();
+
my $mimetype_file = File::Spec->catfile($Bin, '..', 'mimetype');
my %tests = (
@@ -19,11 +26,17 @@ my %tests = (
for my $test (sort keys %tests) {
my $result = $tests{$test};
is(`$^X $mimetype_file --noalign $test`, "$test: $result\n", $test);
+ is($?, 0);
SKIP: {
skip "Skip stdin test because no IO::Scalar", 1 if !$have_io_scalar;
is(`$^X $mimetype_file --noalign --stdin < $test`, "STDIN: $result\n",
"$test (stdin)");
};
+ # with empty mimetype dirs, should exit non-zero
+ `$^X $mimetype_file --database "$empty_dir" --noalign $test`;
+ cmp_ok($?, '>', 0);
}
+
+
done_testing;