mirror of
git://git.code.sf.net/p/zsh/code
synced 2024-11-19 21:44:11 +01:00
277 lines
7.7 KiB
Plaintext
277 lines
7.7 KiB
Plaintext
emulate -L zsh
|
|
setopt extendedglob cbases
|
|
|
|
local opt o_verbose o_list
|
|
|
|
autoload -U zsh-mime-handler
|
|
|
|
while getopts "flv" opt; do
|
|
case $opt in
|
|
# List: show existing suffixes and their handlers then exit.
|
|
(l)
|
|
o_list=1
|
|
;;
|
|
|
|
# Verbose; print diagnostics to stdout.
|
|
(v)
|
|
o_verbose=1
|
|
;;
|
|
|
|
# Force; discard any existing settings before reading.
|
|
(f)
|
|
unset -m zsh_mime_\*
|
|
;;
|
|
|
|
(*)
|
|
[[ $opt = \? ]] || print -r "Option $opt not handled, complain" >&2
|
|
return 1
|
|
;;
|
|
esac
|
|
done
|
|
(( OPTIND > 1 )) && shift $(( OPTIND - 1 ))
|
|
|
|
|
|
if [[ -n $o_list ]]; then
|
|
# List and return.
|
|
for suffix in ${(ko)zsh_mime_handlers}; do
|
|
print ${(r.10.)suffix}${zsh_mime_handlers[$suffix]}
|
|
if [[ -n ${zsh_mime_flags[$suffix]} ]]; then
|
|
print " flags: ${zsh_mime_flags[$suffix]}"
|
|
fi
|
|
done
|
|
return 0
|
|
fi
|
|
|
|
|
|
# Handler for each suffix.
|
|
(( ${+zsh_mime_handlers} )) || typeset -gA zsh_mime_handlers
|
|
# Corresponding flags, if any, for handler
|
|
(( ${+zsh_mime_flags} )) || typeset -gA zsh_mime_flags
|
|
|
|
# Internal maps read from MIME configuration files.
|
|
# Note we don't remember the types, just the mappings from suffixes
|
|
# to handlers and their flags.
|
|
typeset -A suffix_type_map type_handler_map type_flags_map
|
|
|
|
local -a default_type_files default_cap_files
|
|
local -a type_files cap_files array match mbegin mend
|
|
local file line type suffix exts elt flags line2
|
|
integer ind
|
|
|
|
default_type_files=(~/.mime.types /etc/mime.types)
|
|
default_cap_files=(~/.mailcap /etc/mailcap)
|
|
|
|
# Customizable list of files to examine.
|
|
if zstyle -a :mime: mime-types type_files; then
|
|
while (( (ind = ${type_files[(I)+]}) > 0 )); do
|
|
type_files[$ind]=($default_type_files)
|
|
done
|
|
else
|
|
type_files=($default_type_files)
|
|
fi
|
|
|
|
if zstyle -a :mime: mailcap cap_files; then
|
|
while (( (ind = ${cap_files[(I)+]}) > 0 )); do
|
|
cap_files[$ind]=($default_cap_files)
|
|
done
|
|
else
|
|
cap_files=($default_cap_files)
|
|
fi
|
|
|
|
{
|
|
mime-setup-add-type() {
|
|
local type suffix
|
|
local -a array
|
|
|
|
type=$1
|
|
shift
|
|
|
|
while (( $# )); do
|
|
# `.ps' instead of `ps' has been noted
|
|
suffix=${1##.}
|
|
shift
|
|
|
|
if [[ -z $suffix_type_map[$suffix] ]]; then
|
|
[[ -n $o_verbose ]] &&
|
|
print -r "Adding type $type for $suffix" >&2
|
|
suffix_type_map[$suffix]=$type
|
|
else
|
|
# Skip duplicates.
|
|
array=(${=suffix_type_map[$suffix]})
|
|
if [[ ${array[(I)$type]} -eq 0 ]]; then
|
|
[[ -n $o_verbose ]] &&
|
|
print -r "Appending type $type for already defined $suffix" >&2
|
|
suffix_type_map[$suffix]+=" $type"
|
|
fi
|
|
fi
|
|
done
|
|
}
|
|
|
|
# Loop through files to find suffixes for MIME types.
|
|
# Earlier entries take precedence, so the files need to be listed
|
|
# with the user's own first. This also means pre-existing
|
|
# values in suffix_type_map are respected.
|
|
for file in $type_files; do
|
|
[[ -r $file ]] || continue
|
|
|
|
# For once we rely on the fact that read handles continuation
|
|
# lines ending in backslashes, i.e. there's no -r.
|
|
while read line; do
|
|
# Skip blank or comment lines.
|
|
[[ $line = [[:space:]]#(\#*|) ]] && continue
|
|
|
|
# There are two types of line you find in MIME type files.
|
|
# The original simple sort contains the type name then suffixes
|
|
# separated by whitespace. However, Netscape insists
|
|
# on adding lines with backslash continuation with
|
|
# key="value" pairs. So we'd better handle both.
|
|
if [[ $line = *=* ]]; then
|
|
# Gory.
|
|
# This relies on the fact that a typical entry:
|
|
# type=video/x-mpeg2 desc="MPEG2 Video" exts="mpv2,mp2v"
|
|
# looks like a parameter assignment. However, we really
|
|
# don't want to be screwed up by future extensions,
|
|
# so we split the elements to an array and pick out the
|
|
# ones we're interested in.
|
|
type= exts=
|
|
|
|
# Syntactically split line to preserve quoted words.
|
|
array=(${(z)line})
|
|
for elt in $array; do
|
|
if [[ $elt = (type|exts)=* ]]; then
|
|
eval $elt
|
|
fi
|
|
done
|
|
|
|
# Get extensions by splitting on comma
|
|
array=(${(s.,.)exts})
|
|
|
|
[[ -n $type ]] && mime-setup-add-type $type $array
|
|
else
|
|
# Simple.
|
|
mime-setup-add-type ${=line}
|
|
fi
|
|
done <$file
|
|
done
|
|
} always {
|
|
unfunction mime-setup-add-type >&/dev/null
|
|
}
|
|
|
|
# Loop through files to find handlers for types.
|
|
for file in $cap_files; do
|
|
[[ -r $file ]] || continue
|
|
|
|
# Oh, great. We need to preserve backslashes inside the line,
|
|
# but need to manage continuation lines.
|
|
while read -r line; do
|
|
# Skip blank or comment lines.
|
|
[[ $line = [[:space:]]#(\#*|) ]] && continue
|
|
|
|
while [[ $line = (#b)(*)\\ ]]; do
|
|
line=$match[1]
|
|
read -r line2 || break
|
|
line+=$line2
|
|
done
|
|
|
|
# Guess what, this file has a completely different format.
|
|
# See mailcap(4).
|
|
# The biggest unpleasantness here is that the fields are
|
|
# delimited by semicolons, but the command field, which
|
|
# is the one we want to extract, may itself contain backslashed
|
|
# semicolons.
|
|
if [[ $line = (#b)[[:space:]]#([^[:space:]\;]##)[[:space:]]#\;(*) ]]
|
|
then
|
|
# this is the only form we can handle, but there's no point
|
|
# issuing a warning for other forms.
|
|
type=$match[1]
|
|
line=$match[2]
|
|
# See if it has flags after the command.
|
|
if [[ $line = (#b)(([^\;\\]|\\\;|\\[^\;])#)\;(*) ]]; then
|
|
line=$match[1]
|
|
flags=$match[3]
|
|
else
|
|
flags=
|
|
fi
|
|
# Remove quotes from semicolons
|
|
line=${line//\\\;/\;}
|
|
# and remove any surrounding white space --- this might
|
|
# make the handler empty.
|
|
line=${${line##[[:space:]]#}%%[[:space:]]}
|
|
if [[ -z $type_handler_map[$type] ]]; then
|
|
if [[ -n $o_verbose ]]; then
|
|
print -r "Adding handler for type $type:
|
|
$line" >&2
|
|
fi
|
|
type_handler_map[$type]=$line
|
|
type_flags_map[$type]=$flags
|
|
if [[ -n $flags && -n $o_verbose ]]; then
|
|
print -r " with flags $flags" >&2
|
|
fi
|
|
elif [[ -n $o_verbose ]]; then
|
|
print -r "Skipping handler for already defined type $type:
|
|
$line" >&2
|
|
if [[ -n $flags ]]; then
|
|
print -r " with flags $flags" >&2
|
|
fi
|
|
fi
|
|
fi
|
|
done <$file
|
|
done
|
|
|
|
|
|
# Check for styles which override whatever is in the file.
|
|
# We need to make sure there is a handler set up; for some
|
|
# uses we may need to defer checking styles until zsh-mime-handler.
|
|
# How much we need to do here is a moot point.
|
|
zstyle -L | while read line; do
|
|
array=(${(Q)${(z)line}})
|
|
if [[ $array[3] = (handler|flags) && \
|
|
$array[2] = (#b):mime:.([^:]##):(*) ]]; then
|
|
suffix=$match[1]
|
|
# Make sure there is a suffix alias set up for this.
|
|
alias -s $suffix >&/dev/null || alias -s $suffix=zsh-mime-handler
|
|
fi
|
|
done
|
|
|
|
# Now associate the suffixes directly with handlers.
|
|
# We just look for the first one with a handler.
|
|
# If there is no handler, we don't bother registering an alias
|
|
# for the suffix.
|
|
|
|
for suffix line in ${(kv)suffix_type_map}; do
|
|
# Skip if we already have a handler.
|
|
[[ -n $zsh_mime_handlers[$suffix] ]] && continue
|
|
|
|
# Split the space-separated list of types.
|
|
array=(${=line})
|
|
|
|
# Find the first type with a handler.
|
|
line2=
|
|
for type in $array; do
|
|
line2=${type_handler_map[$type]}
|
|
[[ -n $line2 ]] && break
|
|
done
|
|
|
|
# See if there is a generic type/* handler.
|
|
# TODO: do we need to consider other forms of wildcard?
|
|
if [[ -z $line2 ]]; then
|
|
for type in $array; do
|
|
type="${type%%/*}/*"
|
|
line2=${type_handler_map[$type]}
|
|
[[ -n $line2 ]] && break
|
|
done
|
|
fi
|
|
|
|
if [[ -n $line2 ]]; then
|
|
# Found a type with a handler.
|
|
# Install the zsh handler as an alias, but never override
|
|
# existing suffix handling.
|
|
alias -s $suffix >&/dev/null || alias -s $suffix=zsh-mime-handler
|
|
|
|
zsh_mime_handlers[$suffix]=$line2
|
|
zsh_mime_flags[$suffix]=$type_flags_map[$type]
|
|
fi
|
|
done
|
|
|
|
true
|