diff options
Diffstat (limited to 'Functions/MIME/zsh-mime-setup')
-rw-r--r-- | Functions/MIME/zsh-mime-setup | 259 |
1 files changed, 259 insertions, 0 deletions
diff --git a/Functions/MIME/zsh-mime-setup b/Functions/MIME/zsh-mime-setup new file mode 100644 index 000000000..5f9168341 --- /dev/null +++ b/Functions/MIME/zsh-mime-setup @@ -0,0 +1,259 @@ +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 type_files cap_files array match mbegin mend +local file line type suffix exts elt flags line2 + +# Customizable list of files to examine. +zstyle -a :mime: mime-types type_files || + type_files=(~/.mime.types /etc/mime.types) +zstyle -a :mime: mailcap cap_files || + cap_files=(~/.mailcap /etc/mailcap) + +TRAPEXIT() { unfunction mime-setup-add-type >&/dev/null; return 0; } + +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 + + +# 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 |