/usr/share/zsh/functions/MIME/zsh-mime-handler is in zsh-common 5.1.1-1ubuntu2.3.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 | # Handler for MIME types using associative arrays
# zsh_mime_handlers and zsh_mime_flags set up by zsh-mime-setup.
#
# The only flags it handles are copiousoutput and needsterminal.
# copiousoutput is assumed to imply needsterminal. Apart from
# those, it tries to be a bit cunning about quoting, which
# can be a nightmare in MIME handling. If it sees something like
# netscape %s
# and it only has one file to handle (the usual case) then it will handle it
# internally just by appending a file.
#
# Anything else is handled by passing to sh -c, which is the only think
# with a high probability of working. If it sees something with
# quotes, e.g.
# /usr/bin/links "%s"
# it will assume someone else has tried to fix the quoting problem and not
# do that. If it sees something with no quotes but other metacharacters,
# e.g.
# cat %s | handler
# then it will do any quoting and pass the result to sh -c.
# So for example if the argument is "My File", the command executed
# is supposedly
# sh -c 'cat My\ File | handler'
#
# This note is mostly here so you can work out what I tried to do when
# it goes horribly wrong.
local autocd
[[ -o autocd ]] && autocd=autocd
emulate -L zsh
setopt extendedglob cbases nullglob $autocd
# We need zformat from zsh/zutil for %s replacement.
zmodload -i zsh/zutil
autoload -Uz zsh-mime-contexts
# Look for options. Because of the way this is usually invoked,
# (there is always a command to be handled), only handle options
# up to second last argument.
local opt
integer list
while (( $# - $OPTIND > 0 )); do
if getopts "l" opt; then
case $opt in
(l)
list=1
;;
(*)
return 1
;;
esac
else
break
fi
done
shift $(( OPTIND - 1 ))
# Always called with a filename argument first.
# There might be other arguments; don't really know what to do
# with these, but if they came from e.g. `*.ps' then we might
# just as well pass them all down. However, we just take the
# suffix from the first since that's what invoked us via suffix -s.
local suffix s
local -a match mbegin mend
suffix=${1:t}
if [[ $suffix != *.* ]]; then
"No suffix in command: $1" >&2
return 1
fi
suffix=${suffix#*.}
local handler flags no_sh no_bg arg bg_flag="&"
integer i
local -a exec_asis hand_nonex exec_never
# Set to a list of patterns which are ignored and executed as they are,
# despite being called for interpretation by the mime handler.
# Defaults to executable files, which ensures that they are executed as
# they are, even if they have a suffix.
zsh-mime-contexts -a $suffix execute-as-is exec_asis || exec_asis=('*(*)' '*(/)')
zsh-mime-contexts -a $suffix execute-never exec_never
# Set to a list of patterns for which the handler will be used even
# if the file doesn't exist on the disk.
zsh-mime-contexts -a $suffix handle-nonexistent hand_nonex ||
hand_nonex=('[[:alpha:]]#:/*')
# Set to true if the job should be disowned.
zsh-mime-contexts -t $suffix disown && bg_flag="&!"
local pattern
local -a files
# Search some path for the file, if required.
# We do this before any other tests that need to find the
# actual file or its directory.
local dir
local -a filepath
if zsh-mime-contexts -t $suffix find-file-in-path && [[ $1 != /* ]] &&
[[ $1 != */* || -o pathdirs ]]; then
zsh-mime-contexts -a $suffix file-path filepath || filepath=($path)
for dir in $filepath; do
if [[ -e $dir/$1 ]]; then
1=$dir/$1
break
fi
done
fi
# In case the pattern contains glob qualifiers, as it does by default,
# we need to do real globbing, not just pattern matching.
# The strategy is to glob the files in the directory using the
# pattern and see if the one we've been passed is in the list.
local dirpref=${1%/*}
if [[ $dirpref = $1 ]]; then
dirpref=
else
dirpref+=/
fi
for pattern in $exec_asis; do
files=(${dirpref}${~pattern})
if [[ -n ${files[(r)$1]} ]]; then
for pattern in $exec_never; do
[[ ${1:A} = ${~pattern} ]] && break 2
done
if (( list )); then
for (( i = 1; i <= $#; i++ )); do
(( i == 1 )) || print -n " "
arg=${argv[i]}
if [[ -n $arg ]]; then
print -rn -- ${(q)arg}
else
print "''"
fi
done
print
else
"$@"
fi
return
fi
done
if [[ ! -e $1 ]]; then
local nonex_ok
for pattern in $hand_nonex; do
if [[ $1 = ${~pattern} ]]; then
nonex_ok=1
break
fi
done
if [[ -z $nonex_ok ]]; then
if (( list )); then
print -r -- "${(q)@}"
else
"$@"
fi
return
fi
fi
if ! zsh-mime-contexts -s $suffix handler handler; then
# Look for handler starting with longest suffix match.
# Typically we'd only get a match for the shortest, but don't assume so.
s=$suffix
while true; do
handler="${zsh_mime_handlers[$s]}"
if [[ -n $handler ]]; then
break
fi
if [[ $s = *.* ]]; then
s=${s#*.}
else
break
fi
done
if [[ -z $handler ]]; then
if [[ $suffix = *.* ]]; then
print "No handler specified for suffix .$suffix or any final part" >&2
else
print "No handler specified for suffix .$suffix" >&2
fi
return 1
fi
fi
if ! zsh-mime-contexts -s $suffix flags flags; then
# Same again for flags.
s=$suffix
while true; do
flags="${zsh_mime_flags[$suffix]}"
if [[ -n $flags ]]; then
break
fi
if [[ $s = *.* ]]; then
s=${s#*.}
else
break
fi
done
fi
# Set to yes if we use eval instead of sh -c for complicated mailcap lines
# Can possibly break some mailcap entries which expect sh compatibility,
# but is faster, as a new process is not spawned.
zsh-mime-contexts -t $suffix current-shell && no_sh=yes
# Set to yes if the process shouldn't be backgrounded even if it doesn't need a
# terminal and display is set.
zsh-mime-contexts -t $suffix never-background && no_bg=yes
local hasmeta stdin
# See if the handler has shell metacharacters in.
# Don't count whitespace since we can split that when it's unquoted.
if [[ $handler = *[\\\;\*\?\|\"\'\`\$]* ]]; then
hasmeta=1
fi
local -a execargs files
if [[ $handler = *%s* ]]; then
# We need to replace %s with the file(s).
local command
if [[ -n $hasmeta || $# -gt 1 ]]; then
# The handler is complicated, either due to special
# characters or multiple files. We are going to pass it
# down to sh, since it's probably written for sh syntax.
#
# See if it's a good idea to quote the filename(s).
# It isn't if there are already quotes in the handler, since
# that means somebody already tried to take account of that.
if [[ $handler = *[\'\"]* ]]; then
# Probably we ought not even to handle multiple
# arguments, but at least the error message ought
# to make it obvious what's going on.
zformat -f command $handler s:"$argv[1]"
else
zformat -f command $handler s:"${(q)argv[1]}"
fi
if (( list )); then
execargs=(${(Q)${(z)command}} ${argv[1,-1]})
elif [[ $no_sh = yes ]]; then
execargs=(eval $command)
else
execargs=(sh -c $command)
fi
else
# Simple command, one filename.
# Split and add the file without extra quoting,
# since later we will just execute the array as is.
for command in ${=handler}; do
zformat -f command $command s:"$1"
execargs+=($command)
done
fi
else
# If there's no %s, the input is supposed to come from stdin.
stdin=1
if [[ -n $hasmeta && $no_sh != yes && list -eq 0 ]]; then
execargs=(sh -c "$handler")
else
execargs=(${=handler})
fi
fi
if (( list )); then
for (( i = 1; i <= ${#execargs}; i++ )); do
(( i == 1 )) || print -n " "
arg=${execargs[i]}
if [[ -n $arg ]]; then
print -rn -- ${(q)arg}
else
print -n "''"
fi
done
print
return 0
fi
# Now execute the command in the appropriate fashion.
if [[ $flags = *copiousoutput* ]]; then
# We need to page the output.
# Careful in case PAGER is a set of commands and arguments.
local -a pager
zsh-mime-contexts -a $suffix pager pager || pager=(${=PAGER:-more})
if [[ -n $stdin ]]; then
cat $argv | $execargs | $pager
else
$execargs | eval ${PAGER:-more}
fi
elif [[ $no_bg = yes || $flags = *needsterminal* || -z $DISPLAY ]]; then
# Needs a terminal, so run synchronously.
# Obviously, if $DISPLAY is empty but the handler needs a
# GUI we are in trouble anyway. However, it's possible for
# the handler to be smart about this, like pick-web-browser,
# and even if it just produces an error message it's better to
# have it run synchronously.
if [[ -n $stdin ]]; then
cat $argv | $execargs
else
$execargs
fi
else
# Doesn't need a terminal and we have a $DISPLAY, so run
# it in the background. sh probably isn't smart enough to
# exec the last command in the list, but it's not a big deal.
#
# The following Rococo construction is to try to make
# the job output for the backgrounded command descriptive.
# Otherwise it's equivalent to removing the eval and all the quotes,
# including the (q) flags.
if [[ -n $stdin ]]; then
eval cat ${(q)argv} "|" ${(q)execargs} $bg_flag
else
eval ${(q)execargs} $bg_flag
fi
fi
|