#!/bin/zsh -f ############################################################################## # # Original code by Lynn C. Robinson. # Maintainership taken over by Christian J. Robinson # # Copyright 1990(?) - 1999 Lynn C. Robinson # Copyright 1999 - 2007 Christian J. Robinson # # You may copy/use this under the terms of the GNU General Public License, # version 2 or later. # # $Id: vv,v 1.18 2008/03/27 02:56:54 infynity Exp $ # # Changelog: {{{1 # # $Log: vv,v $ # Revision 1.18 2008/03/27 02:56:54 infynity # *** empty log message *** # # Revision 1.17 2007/08/31 17:46:02 infynity # rm -r => rm -rf # # Revision 1.16 2007/08/07 07:03:31 infynity # Test for a URI argument # # Revision 1.15 2007/08/03 04:29:47 infynity # *** empty log message *** # # Revision 1.14 2007/08/01 07:23:49 infynity # View files within archives with a handler, if possible # Separated config from help # # Revision 1.13 2007/07/21 06:45:58 infynity # *** empty log message *** # # Revision 1.12 2007/07/21 06:44:34 infynity # .lrp files are .tar.gz files # # Revision 1.11 2007/07/10 16:55:08 infynity # Somehow missed out the .gz and .bz2 non-large file handlers # # Revision 1.10 2007/07/08 11:44:12 infynity # cbz/cbr added # # Revision 1.9 2007/06/22 12:15:12 infynity # *** empty log message *** # # Revision 1.8 2007/06/22 12:14:16 infynity # Allow viewing files within RPMs. # # Revision 1.7 2007/06/04 11:39:08 infynity # *** empty log message *** # # Revision 1.6 2007/06/04 11:35:29 infynity # Allow handling of URIs # # Revision 1.5 2006/07/16 02:55:22 infynity # *** empty log message *** # # Revision 1.4 2006/06/16 18:48:46 infynity # Configurable multi-part extensions. # # Revision 1.3 2006/04/29 07:35:53 infynity # Try to gracefully handle some instances where a viewer isn't available. # # Revision 1.2 2006/04/29 06:56:47 infynity # *** empty log message *** # # Revision 1.1 2006/04/23 03:29:13 infynity # Initial revision # # Apr 22, 2006 - Near total rewrite. # # Apr 20, 2006 - .jar and .xpi files are just zip files. # # Jan 30, 2004 - Add unrar support. # # Oct 15, 2001 - Support for .pdf and .rpm files. # # Jun 30, 2000 - Support for a few anim formats. (mov, avi, qt, mpg) # # May 09, 2000 - Support for .ps files. # - Use the "file" utility to try to determine what to do with # unknown file types. (Experimental.) # # Nov 10, 1999 - Added handling for images. # # May 28, 1999 - Made it possible to view files in tar* archives, instead of # just list them. # # May 14, 1999 - Made filename matching case insensitive. (Actually, I just # converted the filename to all lowercase for the matching.) # # }}}1 # # TODO: Use the return value of the file utility a lot more. # Find a way to use mime types? # ############################################################################## # Initialize: {{{1 # Do this even before sourcing the config file: typeset -A multi_extensions uri_protocols # Do this before anything else so it can't clobber internally needed stuff: . ~/.vv-config 2>/dev/null Version="3.1 BETA August 07, 2007" RCSVersion='$Revision: 1.18 $' # ' RCSVersion=${${=RCSVersion}[-2]} RCSDate='$Date: 2008/03/27 02:56:54 $' # ' RCSDate=${${=RCSDate}[2]} # Set some viewers if they're not set: : ${PAGER:=less} : ${IMAGE_VIEWER:=$(whence xv || whence eog || echo 'no_viewer image')} : ${ANIM_VIEWER:=mplayer} : ${HTML_VIEWER:=$(whence w3m || whence links || whence lynx || echo 'no_viewer html')} : ${PS_VIEWER:=$(whence gv || whence ghostview || echo 'no_viewer postscript')} : ${PDF_VIEWER:=$(whence gv || whence xpdf || echo 'no_viewer pdf')} # Some files have multiple extensions: typeset -A default_multi_extensions default_uri_protocols default_multi_extensions[tar.*]='tar.%ext%' default_multi_extensions[html.*]='html.%ext%' default_multi_extensions[htm.*]='htm.%ext%' default_uri_protocols[http]='html' default_uri_protocols[https]='html' BASENAME=${0:t} if [[ -z "$HTML_FORCE_HTML_OPT" ]] then case ${=HTML_VIEWER} in *w3m) HTML_FORCE_HTML_OPT='-T text/html' ;; *links) HTML_FORCE_HTML_OPT='-default-mime-type text/html' ;; *lynx) HTML_FORCE_HTML_OPT='-force_html' ;; esac fi RAR=$(whence rar || whence unrar || echo 'no_viewer rar') [[ "$PAGER[-4,-1]" == "less" ]] && LESSFORCEOPT="-f" if [[ ! -z "$TMPDIR" ]] then export TMPPREFIX=$TMPDIR/vv-$$- else export TMPPREFIX=/usr/tmp/vv-$$- fi setopt NULL_GLOB # Suppress glob error message. ulimit -f 58594 # limit file size to 58594 512 byte blocks ( ~30meg ) TRAPINT() { #echo "\rInterrupt received, cleaning up..." #echo "/bin/rm -v ${TMPPREFIX}*$$" #echo " produced the output:" #/bin/rm -v ${TMPPREFIX}*$$ /bin/rm -rf ${TMPPREFIX}* > /dev/null 2>&1 exit 1 } # Default large file handlers: {{{1 internal_view_zoo_big() # {{{2 { if [[ "X$2" == "X-a" || "`zoo lq $1 | wc -l`" -eq 1 ]] then $PAGER =(zoo epq $1) elif [[ ! -z "$2" ]] then $PAGER =(zoo ep $*) else $PAGER =( zoo V $1 zoo ep $1 \ \*read\* \*READ\* \*Read\* \*doc \*man \*txt) fi } internal_view_zip_big internal_view_jar_big internal_view_xpi_big internal_view_cbz_big() # {{{2 { if [[ "X$2" == "X-a" || "`unzip -qql $1 | wc -l`" -eq 1 ]] then $PAGER =(unzip -c $1) elif [[ ! -z "$2" ]] then $PAGER =(unzip -p $*) else $PAGER =( unzip -v $1 unzip -p $1 \ \*read\* \*READ\* \*Read\* \*doc \*man \*txt ) fi } internal_view_rar_big internal_view_cbr_big() # {{{2 { if [[ "X$2" == "X-a" || "`$RAR lb $1 | wc -l`" -eq 1 ]] then $PAGER =(${=RAR} p $1) elif [[ ! -z "$2" ]] then $PAGER =(${=RAR} -inul p $*) else $PAGER =( ${=RAR} l $1 ${=RAR} -inul p $1 \ \*read\* \*READ\* \*Read\* \*doc \*man \*txt ) fi } internal_view_gz_big() # {{{2 { $PAGER =(zcat $*) } internal_view_bz2_big() # {{{2 { $PAGER =(bzcat $*) } # Default file handlers: {{{1 internal_view_zoo() # {{{2 { if [[ "X$2" == "X-a" || "`zoo lq $1 | wc -l`" -eq 1 ]] then zoo epq $1 | $PAGER elif [[ ! -z "$2" ]] then zoo ep $* | $PAGER else ( zoo V $1 zoo ep $1 \ \*read\* \*READ\* \*Read\* \*doc \*man \*txt ) | $PAGER fi } internal_view_zip internal_view_jar internal_view_xpi internal_view_cbz() # {{{2 { if [[ "X$2" == "X-a" || "`unzip -qql $1 | wc -l`" -eq 1 ]] then unzip -c $1 | $PAGER elif [[ ! -z "$2" ]] then unzip -p $* | $PAGER else ( unzip -v $1 unzip -p $1 \ \*read\* \*READ\* \*Read\* \*doc \*man \*txt ) | $PAGER fi } internal_view_rar internal_view_cbr() # {{{2 { if [[ "X$2" == "X-a" || "`$RAR lb $1 | wc -l`" -eq 1 ]] then $RAR p $1 | $PAGER elif [[ ! -z "$2" ]] then $RAR -inul p $* | $PAGER else ( $RAR l $1 $RAR -inul p $1 \ \*read\* \*READ\* \*Read\* \*doc \*man \*txt ) | $PAGER fi } internal_view_gz() # {{{2 { zcat $* | $PAGER } internal_view_bz2() # {{{2 { bzcat $* | $PAGER } internal_view_tar() # {{{2 { if [[ $# -gt 1 ]] then tar -xOf $* | $PAGER else tar -tvvf $* | $PAGER fi } internal_view_lrp internal_view_tgz internal_view_tar.z internal_view_tar.gz() # {{{2 { if [[ $# -gt 1 ]] then tar -xzOf $* | $PAGER else tar -tzvvf $* | $PAGER fi } internal_view_tar.bz2() # {{{2 { if [[ $# -gt 1 ]] then bunzip2 -c $1 | tar -xO ${@[2,-1]} | $PAGER else bunzip2 -c $* | tar -tvv | $PAGER fi } internal_view_html.gz internal_view_htm.gz() # {{{2 { ${=HTML_VIEWER} ${=HTML_FORCE_HTML_OPT} =(zcat $*) } internal_view_html.bz2 internal_view_htm.bz2() # {{{2 { ${=HTML_VIEWER} ${=HTML_FORCE_HTML_OPT} =(bzcat $*) } internal_view_htm internal_view_html() # {{{2 { ${=HTML_VIEWER} ${=HTML_FORCE_HTML_OPT} $* } internal_view_ps() # {{{2 { if [[ ! -z $DISPLAY ]] then ${=PS_VIEWER} $* else echo "This is a postscript file, and you do not appear to have a GUI running." read -q REPLY\?"I can run the file through 'ps2ascii', but the output will look bad. Continue? " if [[ "$REPLY" == 'y' ]] then ps2ascii $* | $PAGER fi fi } internal_view_pdf() # {{{2 { if [[ ! -z $DISPLAY ]] then ${=PDF_VIEWER} $* else echo "This is a pdf file, and you do not appear to have a GUI running." read -q REPLY\?"I can run the file through 'ps2ascii', but the output will look bad. Continue? " if [[ "$REPLY" == 'y' ]] then ps2ascii $* | $PAGER fi fi } # Image viewers: {{{2 internal_view_gif \ internal_view_jpg \ internal_view_jpeg \ internal_view_tif \ internal_view_tiff \ internal_view_bmp \ internal_view_xpm \ internal_view_xbm \ internal_view_ppm \ internal_view_png \ internal_view_tga \ internal_view_pcx() { if [[ ! -z $DISPLAY ]] then ${=IMAGE_VIEWER} $* else if whence zgv > /dev/null then zgv $* else echo "Don't have a way to display images in the current display mode,\nor your DISPLAY variable isn't set." fi fi } # Animation/movie viewers: {{{2 internal_view_wmv \ internal_view_mov \ internal_view_avi \ internal_view_mpg \ internal_view_mpeg \ internal_view_qt \ internal_view_rm() { if [[ ! -z $DISPLAY ]] then ${=ANIM_VIEWER} $* else echo "Don't have a way to display anims in the current display mode,\nor your DISPLAY variable isn't set." fi } internal_view_rpm() # {{{2 { local rpmtmp archive if [[ $# -gt 1 ]] then rpmtmp=$(/bin/mktemp -d ${TMPPREFIX}rpm.XXXXXX) #rpm -i --root $rpmtmp --nodeps --noscripts --nouser --nogroup --nomtime --nomode --nordev $1 archive=$PWD/$1 shift cd $rpmtmp rpm2cpio $archive | cpio -di --quiet #$PAGER ${*/#/$rpmtmp} $PAGER .$* cd - /bin/rm -rf $rpmtmp else rpm -qvlip $* | $PAGER fi } # }}}1 no_viewer() # {{{1 { echo "$BASENAME: ERROR: I can't find an executable to view $1 files." } # }}}1 find_handler() # {{{1 { local extension big_file tmp i handler big_file=0 for i in ${(k)default_uri_protocols} ${(k)uri_protocols} do if [[ $1 == $i://* ]] then extension=${uri_protocols[$i]:-$default_uri_protocols[$i]} fi done if [[ -z "$extension" ]] then [[ ! -z "`echo ${1}*(L-400000)`" ]] && big_file=1 2>&/dev/null extension=${(L)1:e} for i in ${(k)default_multi_extensions} ${(k)multi_extensions} do if eval \[\[ \$1 \== \*.$i \]\] then tmp=${multi_extensions[$i]:-$default_multi_extensions[$i]} tmp=${tmp:s/%ext%/$extension/} extension=$tmp fi done fi if [[ $big_file == 1 ]] && type view_${extension}_big > /dev/null then handler="view_${extension}_big" elif [[ $big_file == 1 ]] && type internal_view_${extension}_big > /dev/null then handler="internal_view_${extension}_big" elif type view_${extension} > /dev/null then handler="view_${extension}" elif type internal_view_${extension} > /dev/null then handler="internal_view_${extension}" else handler="" fi echo $handler } # }}}1 view() # {{{1 # Arguments: # 1 - The file to view # 2..N - The files within the archive to view # Return value: # 0 - A handler was found or the named file didn't exist # 1 - No handler was found { local i handler local -a handlers if [[ ! -e $1 && $1 != *://* ]] then echo "$BASENAME: $1: No such file or directory" >&2 return 0 fi handler=$(find_handler $1) let i=1 while [[ $((++i)) -le $# ]] do handlers[$i]=$(find_handler $*[$i]) done if [[ ! -z "$handler" ]] then if [[ $# -gt 1 ]] then # A major kluge, and will fail in interesting ways depending on the code # of the handlers, but generally it works: let i=1 while [[ $((++i)) -le $# ]] do tmp==(PAGER=/bin/cat $handler $1 $*[$i] 2>/dev/null) if [[ -s "$tmp" ]] then ${handlers[$i]:=$PAGER} $tmp else ${handlers[$i]:=$PAGER} $*[$i] fi done else $handler $* fi return 0 else return 1 fi } # }}}1 if [[ "$1" == "--version" || "X$1" == "X-v" ]] # {{{1 then echo "$BASENAME version $Version (RCS revision: $RCSVersion $RCSDate)" echo "(C) Copyright 1990 - 2007 Lynn C. and Christian J. Robinson\n" echo "You may copy/use this under the terms of the GNU General Public License," echo "version 2 or later." exit fi if [[ "$1" == "--help" || "X$1" == "X-h" ]] # {{{1 then /bin/cat <" in ~/.vv-config -- for example, to handle .baz files: view_baz() { bazview \$* } The return value from this function is never checked -- it is assumed that if there's a handler for an extension it will properly view the file. You can also have a "view__big" function that does the same thing as the "view_" function when the file is larger than about thirty megabytes, but it isn't necessary (see this script's code for examples). Make sure you user $PAGER instead of less/more in your handlers. There are also some variables you can set in the config file: IMAGE_VIEWER - The program to use to view most image formats. ANIM_VIEWER - The program to use to view most movie file formats (avi, etc.) PDF_VIEWER - The program to use to view pdf or postscript files. HTML_VIEWER - The program to use to view HTML files (don't use a GUI browser!) HTML_FORCE_HTML_OPT - The options necessary to force the HTML_VIEWER to interpret the file as HTML. If you have a special "multi-part" extension you can configure them like this (these are defaults): multi_extensions[tar.*]='tar.%ext%' multi_extensions[html.*]='html.%ext%' multi_extensions[htm.*]='htm.%ext%' You can also map url://example.com/ URIs to viewer functions like this (these are defaults): uri_protocols[http]='html' EOF exit fi # }}}1 [[ $# == 0 ]] && $0 --help >&2 && exit 1 view $* && exit for i in $* # {{{1 do view $i && continue FILE_OUT=$(file -Lb $i) case "$FILE_OUT" in *text*) $PAGER $i ;; *executable*) echo "$BASENAME: $i:" read -q REPLY\?"This is a binary executable, pipe through 'strings'? " if [[ "$REPLY" == 'y' ]] then strings $i | $PAGER else read -q REPLY\?"View with $PAGER anyway? " [[ "$REPLY" == 'y' ]] && $PAGER $LESSFORCEOPT $i fi ;; *data*) echo "$BASENAME: $i:" read -q REPLY\?"This is a potentially unreadable data file, pipe through 'strings'? " if [[ "$REPLY" == 'y' ]] then strings $i | $PAGER else read -q REPLY\?"View with $PAGER anyway? " [[ "$REPLY" == 'y' ]] && $PAGER $LESSFORCEOPT $i fi ;; *) $PAGER $i ;; esac done # vim:ts=2:sw=2:ai:fo=croq2: # vim600:fdm=marker:fdc=3: