http://qs1969.pair.com?node_id=299044
Category: Miscellaneous
Author/Contact Info #include

Riotmod.com

Description: I've always liked the Windows "start" commandline utility. It opens any file passed to it with the appropriate program. For example, issuing "start mysong.mp3" will open "mysong.mp3" with the default MP3 player, etc. "start" is my attempt to write a similar utility for *NIX systems. "start" uses the GNU utility "file" to determine a file's MIME type, and looks in a local flatfile database for a "command association" (in other words, the program that that MIME type is assigned to). If there isn't an entry present, it asks the user for a program to associate with that MIME type. "start" can be run in commandline mode, or (if you start it with the "-g" flag and no other arguments) it can be used with a Tk GUI. POD documentation has been included. Heavily commented.

REQUIREMENTS: GNU utility file, Perl, Tk

#!/usr/bin/perl
#
# start
#
# =========================================
#              INFORMATION
# =========================================
#
# Author: Dan Hetrick
# Revision: 0.41
# License: GPL
# Platform: *NIX
#
# =========================================
#              REQUIREMENTS
# =========================================
#
# Perl
# file (*NIX utility)
# Perl/Tk
#
# =========================================
#              DESCRIPTION
# =========================================
#
# Opens an applications with different
# applications depending on it's MIME type.
# It stores the user's MIME-executable
# association in a flatfile database
# in the user's home directory.
# If a MIME type is encountered that
# doesn't have a database entry, start
# displays a dialog for the user to
# enter a command association.
# Commands are entered in this format:
#
# <command>
#
# The filename is appended to the command
# when an associated file is open.
#
# Example:
# You try to open a file with a MIME type
# of 'text/ascii'.  It's not in the
# database, so the program prompts you
# for a command.  You want to open text
# files with 'vi', so you enter this as the
# command:
#
# vi
#
# The program then executes 'vi filename'
# to open the file.  If you want the
# program to detach from the console,
# add an exclamation point to the command:
#
# !xmms
#
# This will execute 'xmms filename &'.
#
# =========================================
#                 USAGE
# =========================================
#
# To use as a commandline tool:
# $ start <filename>
#
# To use as a GUI tool:
# $ start -gui   -or-   start -g
#
# =========================================
#                 CHANGELOG
# =========================================
#
# Version 0.41
#      - Refined the display modes.  The commandline
#        mode now ONLY uses STDIN/STDOUT for display,
#        and GUI mode uses Tk dialogs to get user
#        input.
#      - No longer exits after it creates its
#        initial database.
#      - Added the changelog to the script source.
#      - Added more comments to the source code.
#      - Fixed some spelling problems in the
#        documentation, and changed the "Installation"
#        section.
#      - Changed the way the program stores associations.
#        When it stores a MIME type/command, it will
#        try to open the file with the associated
#        command rather than exiting (as it did in 0.4).
#      - Now tells the user when it creates a blank
#        database.
#      - Added application name, version, and
#        copyleft info to the GUI displays and
#        the commandline display.
#      - Cleaned up and refined the GUI
#      - Fixed some bugs in command storage
#      - Executable files that are passed to start
#        are now exec'ed, rather than ran against
#        the association database
#
# Version 0.4
#      - Initial release.
#      - Uses Version 0.1 of the start makeself.sh installer.
#
# =========================================
#              SCRIPT BEGIN
# =========================================
#
# Set some miscellaneous variables
my $APPNAME="start"; # Application name
my $VERSION="0.41"; # Version
my $APPDB="$ENV{HOME}/.start_mass"; # The location of the MIME databas
+e
my $GUI_MODE=0; # Use Tk dialogs ONLY
my $CL_MODE=1; # Use STDIN/STDOUT ONLY

# Sets commandline interface for the default
my $DISPLAY_MODE=$CL_MODE;

# Check to see if a database is present,
# and if not, create one before we continue
if(-e "$APPDB"){}else{ CreateDatabase(); }

# Check to see if there's enough arguments,
# print the usage and exit if not.
if( ($#ARGV!=0) && (-e "$APPDB") )
{
    Usage();
}

# Check if we're running in commandline or GUI mode
if($ARGV[0]=~/-g/) { $DISPLAY_MODE=$GUI_MODE; GUI_OpenApplication(); }
+ else { $DISPLAY_MODE=$CL_MODE; OpenApplication($ARGV[0]); }

# =========================================
#               SCRIPT END
# =========================================
#
# =========================================
#         SUPPORT SUBROUTINES START
# =========================================
#
# =========================================
#           SUB DESCRIPTION START
# =========================================
#
# ================
# CreateDatabase()
# ================
# Creates a blank MIME database in the user's HOME directory
#
# =======
# Usage()
# =======
# Prints usage information to STDOUT and exits
#
# ==========================
# OpenApplication($filename)
# ==========================
# Opens a file with its associated application,
# prompting the user for an association if there
# isn't one in the database
#
# ================================
# ProcessCommand(command,filename)
# ================================
# This 'parses' the associated command, and returns a complete
# commandline to be executed.
#
# ==============================================
# AddApplication($mime_type,$associated_command)
# ==============================================
# Adds a MIME type and its associated command
# to the MIME database
#
# ========================
# GUI_GetInput($mime_type)
# ========================
# Gets a command from the user to associate with
# a MIME type, using a Tk GUI, then opens the
# file with the associated command.
#
# =======================
# CL_GetInput($mime_type)
# =======================
# Gets a command from the user to associate with
# a MIME type, STDIN/STDOUT, then opens the file
# with the associated command.
#
# =====================
# GUI_OpenApplication()
# =====================
# Uses a Tk GUI to interface the
# OpenApplication() subroutine
#
# =========================================
#            SUB DESCRIPTION END
# =========================================
#
# ================
# CreateDatabase()
# ================
# Arguments: None
# Returns: Nothing
# Description: Creates a blank database for
#              start to use in the user's
#              HOME directory.
sub CreateDatabase
{
    print "Creating user database ($APPDB)...";
    open(APPDEF,">$APPDB");
    print APPDEF "# $APPNAME $VERSION\n# MIME Type Database\n# Do not 
+edit\n";
    close APPDEF;
    print "done!\n";
}

# ================
# Usage()
# ================
# Arguments: None
# Returns: Nothing
# Description: Prints usage information to
#              STDOUT, then exits.
sub Usage
{
    print "\n$APPNAME $VERSION\n";
    print "(c)Copyleft Dan Hetrick 2003\n\n";
    print "Commandline Mode:\nstart <filename>\n\n";
    print "GUI Mode:\nstart -gui\n\n";
    exit;
}

# ================
# OpenApplication()
# ================
# Arguments: Filename
# Returns: Nothing
# Description: Uses 'file' to get a Filename's
#              MIME type, and looks it up in
#              the database.  If there's no
#              entry, it calls GUI_GetInput().
sub OpenApplication
{
    my($filename)=@_;
    if( (-e "$APPDB") && (-e "$filename") )
    {
        $mime_type=`file -ib $filename`;
        chomp $mime_type;
        # Check to see if the file
        # is executable;  if so,
        # execute it
        if($mime_type=~/executable/)
        {
            exec "$filename";
        } else {
            open(APPDEF,"<$APPDB");
            @appdat=<APPDEF>;
            close APPDEF;
            foreach $ad (@appdat)
            {
                if (index($ad,"#")==0) { next; }
                if($ad=~/$mime_type/)
                {
                    my @apd=split('==',$ad);
                    $happ=$apd[1];
                    chomp $happ;
                    my $com=ProcessCommand($happ,$filename);
                    exec "$com";
                }
            }
            # MIME type not found
            # Get user input to associate a
            # command with the MIME type
            if($DISPLAY_MODE==$GUI_MODE)
            {
                GUI_GetInput($mime_type,$filename);
            } else {
                CL_GetInput($mime_type,$filename);
            }
        }

    } 
}

# ================
# ProcessCommand()
# ================
# Arguments: Command,Filename
# Returns: Executable commandline
# Description: This 'parses' the associated
#              command, and returns a complete
#              commandline.
sub ProcessCommand
{
    my($cmdline,$filename)=@_;
    if (index($cmdline,"!")==0) # detatch command
    {
        my $rcm=substr($cmdline,1);
        return "$rcm $filename&";
    } else {
        return "$cmdline $filename";
    }
}


# ================
# AddApplication()
# ================
# Arguments: MIME type, Command
# Returns: Nothing
# Description: Adds a MIME type and its
#              associated command to the user's
#              start database.
sub AddApplication
{
    my($mime_type,$file_command)=@_;
    open(APPDEF,">>$APPDB");
    print APPDEF "$mime_type==$file_command\n";
    close APPDEF;
}

# ================
# GUI_GetInput()
# ================
# Arguments: MIME type, filename
# Returns: Nothing
# Description: Prompts the user for a command to
#              associate with a MIME type,
#              then writes them both to the
#              database with AddApplication().
#              Then, it opens the file with
#              OpenApplication().
sub GUI_GetInput
{
    my($mime_type,$filename)=@_;
    use Tk;
    my $mw = MainWindow->new();
    $mw->title("Enter Command");
    $mw->Label(-bitmap=>'question')->pack(-anchor=>'nw',-side=>'left',
+-padx=>5);
    $mw->Label(-text=>"Please enter a command to associate with this M
+IME type:")->pack();
    $mw->Label(-text=>"$mime_type")->pack();
    $mw->Entry(-width => 25, -textvariable, \$incom)->pack(-anchor => 
+'nw',-fill=>'x');
    $mw->Label(-text=>"Start with a ! to detach from console.")->pack(
+-fill=>'x');
    $mw->Button(-text => "Ok",
            -command => sub { AddApplication($mime_type,$incom); OpenA
+pplication($filename); } )
            ->pack(-side => 'top',
            -anchor => 'nw',-fill=>'x');
    $mw->Button(-text => "Cancel",
            -command => sub { exit; })
            ->pack(-side => 'top',
            -anchor => 'nw',-fill=>'x');
    MainLoop;
}

# ================
# CL_GetInput()
# ================
# Arguments: MIME type
# Returns: Nothing
# Description: Prompts the user for a command to
#              associate with a MIME type,
#              then writes them both to the
#              database with AddApplication().
#              Then, it opens the file with
#              OpenApplication().
sub CL_GetInput
{
    my($mime_type,$filename)=@_;
    print "$APPNAME $VERSION\n";
    print "(c)Copyleft Dan Hetrick 2003\n\n";
    print "Please enter a command to associate with this MIME type:\n"
+;
    print "$mime_type\n";
    print "Start with a ! to detach from console\n";
    print "\nCommand: ";
    my $in_command=<STDIN>;
    print "Adding command to database...";
    AddApplication($mime_type,$in_command);
    print "done!\nOpening $filename...\n";
    OpenApplication($filename);
}

# ================
# GUI_OpenApplication()
# ================
# Arguments: None
# Returns: Nothing
# Description: Prompts the user for a filename
#              to open with OpenApplication().
sub GUI_OpenApplication
{
    use Tk;
    my $mw = MainWindow->new();
    $mw->title("$APPNAME $VERSION");
    $mw->Label(-bitmap=>'questhead')->pack(-fill=>'x',-side=>"left");
    $mw->Label(-text=>"Open File...")->pack(-fill=>'x',-side=>"left");
    $mw->Entry(-width => 40, -textvariable, \$text)->pack(-anchor => '
+nw',-fill=>'x',-side=>"left");
    $mw->Button(-text => "Ok",
            -command => sub { OpenApplication($text); } )
            ->pack(-side => 'top',
            -anchor => 'nw',-fill=>'x',-side=>"left");
    $mw->Button(-text => "Cancel",
            -command => sub { exit; })
            ->pack(-side => 'top',
            -anchor => 'nw',-fill=>'x',-side=>"left");
    MainLoop;
}
# =========================================
#         SUPPORT SUBROUTINES END
# =========================================
__END__

=pod

=head1 NAME

B<start>

A utility to open files with the user's choice of
application, for *NIX.  Based on the Windows
"start" commandline utility.

=head1 VERSION

0.41

=head1 USAGE

Commandline mode:

C<$ start I<filename>>

Graphical mode:

C<$ start -g>

B<I<-or->>

C<$ start -gui>

=head1 DESCRIPTION

Opens an applications with different applications depending on it's MI
+ME type.  It stores the user's MIME-executable association in a flatf
+ile database in the user's home directory.  If a MIME type is encount
+ered that doesn't have a database entry, start displays a dialog for 
+the user to enter a command association.  Commands are entered in thi
+s format:

<command>

Put a "!" in front of the command if you want to detach it from the co
+nsole.

Example:  You want to open a file with a MIME type of "text/ascii".  T
+o open it with 'vi', you'd enter the command:

vi

If you wanted it to open in KEdit, and detach it from the console, you
+'d enter the command:

!kedit

=head1 INSTALLATION

Copy B<start> to any directory on your PATH.

=head1 AUTHOR

Dan "Wraithnix" Hetrick

=head1 CONTACT

AIM: C<Wraithnix>

ICQ: C<28499891>

IRC: C<irc.gamesnet.net:6667, #shogomad>

Yahoo! Instant Messenger: C<smoking_crack_with_jesus>

Email: C<dhetrick at riotmod dot com>.

=head1 HOMEPAGE

http://www.riotmod.com/

=head1 CHANGELOG

B<Version 0.41>

Refined the display modes.  The commandline mode now ONLY uses STDIN/S
+TDOUT for display, and GUI mode uses Tk dialogs to get user input.

No longer exits after it creates its initial database.

Added the changelog to the script source.

Added more comments to the source code.

Fixed some spelling problems in the documentation, and changed the "In
+stallation" section.

Changed the way the program stores associations.  When it stores a MIM
+E type/command, it will try to open the file with the associated comm
+and rather than exiting (as it did in 0.4).

Now tells the user when it creates a blank database.

Added application name, version, and copyleft info to the GUI displays
+ and the commandline display.

Cleaned up and refined the GUI.

Fixed some bugs in command storage.

Executable files that are passed to start are now exec'ed, rather than
+ ran against the association database

B<Version 0.4>

Initial release.

Uses Version 0.1 of the start makeself.sh installer.

=head1 COPYRIGHT

Free, free, free.

This program is free software, and is released under the GPL.

The author is not responsible for any use of this software, nor is he 
+responsible
for anything the use of this software does to the user's computer.
Any use of this software, in I<any> way, including viewing its source 
+code, implies
agreement with the previous statement.
Replies are listed 'Best First'.
Re: start
by zentara (Archbishop) on Oct 14, 2003 at 15:39 UTC
    Nice idea, but I use mc to navigate and it does it for me. Just for people not familiar with "MidnightCommander".... I've been using mc to do this under linux. The mc.ext file is loaded with regexes to autostart programs. All I need is to hit 'enter' on the file. Of course, your checking of mime types gives more flexibility in naming(no extension worries),
    include/image # Open=if [ "$DISPLAY" = "" ]; then zgv %f; else (ee %f &); fi Open= xv %f 2>&1>/dev/null & View=%view{ascii} identify %f #View=%view{ascii} asciiview %f
      I've never used MidnightCommander. Actually, I wrote this for a friend of mine. He wanted something like this for use in shell scripts (I'm not sure why), and it needed to be "extension ignorant". I ended up spending a lot more time on it than I planned on, and voila! There it is.

      A genius writes code an idiot can understand, while an idiot writes code the compiler can't understand.