#! @SHELL@ # Copyright (C) 2006 Free Software Foundation # Written by Paolo Bonzini. # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published # by the Free Software Foundation; either version 2 of the License, # or (at your option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # POSIX and NLS nuisances, taken from autoconf. if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then emulate sh NULLCMD=: # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST else case `(set -o) 2>/dev/null` in *posix*) set -o posix;; esac fi BIN_SH=xpg4; export BIN_SH # for Tru64 DUALCASE=1; export DUALCASE # for MKS sh if test "${LANG+set}" = set; then LANG=C; export LANG; fi if test "${LC_ALL+set}" = set; then LC_ALL=C; export LC_ALL; fi if test "${LC_MESSAGES+set}" = set; then LC_MESSAGES=C; export LC_MESSAGES; fi if test "${LC_CTYPE+set}" = set; then LC_CTYPE=C; export LC_CTYPE; fi # Also make sure CDPATH is empty, and IFS is space, tab, \n in that order. # Be careful to avoid that editors munge IFS (unset CDPATH) >/dev/null 2>&1 && unset CDPATH IFS=" "" "" " : ${TMPDIR=/tmp} : ${ZIP="@ZIP@"} : ${UNZIP="@UNZIP@"} progname="$0" # Emit a usage message and exit with error status 1 usage () { cat >&2 <&2 (exit 1); exit 1 } # Usage: copy SRC DEST # Copy file SRC to directory DEST, which is the staging area of the jar file. # Fail if it is already present or if it is not a regular file. copy () { if test -f "$1"; then # A simple optimization. Optimistically assuming that ln will work # cuts 60% of the run-time! if ln "$1" "$2"/"$1" > /dev/null 2>&1; then return 0 fi if test -f "$2"/"$1"; then error "$1": Duplicate entry. fi dir=`dirname "$1"` $mkdir_p "$2"/"$dir" ln "$1" "$2"/"$1" > /dev/null 2>&1 || cp "$1" "$2"/"$1" elif test -e "$1"; then error "$1": Invalid file type. else error "$1": File not found. fi } # Make a temporary directory and store its name in the JARTMP variable. make_tmp () { test -n "$JARTMP" && return { JARTMP=`(umask 077 && mktemp -d "$TMPDIR/jarXXXXXX") 2>/dev/null` && test -n "$JARTMP" && test -d "$JARTMP" } || { JARTMP=$TMPDIR/jar$$-$RANDOM (umask 077 && mkdir "$JARTMP") } || exit $? trap 'exit_status=$? if test -n "$JARTMP"; then rm -rf "$JARTMP"; fi exit $exit_status' 0 } # Usage: make_manifest destfile kind [source-manifest] # Create a manifest file and store it in destfile. KIND can be "default", # or "user", in which case SOURCE-MANIFEST must be specified as well. make_manifest () { dir=`dirname "$1"` $mkdir_p "$dir" case $2 in default) cat > "$1" <<\EOF Manifest-Version: 1.0 Created-By: @VERSION@ EOF ;; user) cp "$3" "$1" ;; esac } # Usage: set_var var [value] # Exit with an error if set_var was already called for the same VAR. Else # set the variable VAR to the value VALUE (or the empty value if no parameter # is given). set_var () { if eval test x\$set_$1 = xset; then error Incompatible or repeated options. else eval $1=\$2 eval set_$1=set fi } # Process the arguments, including -C options, and copy the whole tree # to $JARTMP/files so that zip can be invoked later from there. make_files () { change=false if $process_response_files; then if test $# = 0; then while read arg; do make_files_1 "$arg" done else for infile do exec 5<&0 exec 0< $infile while read arg; do make_files_1 "$arg" done exec 0<&5 exec 5<&- done fi else for arg do make_files_1 "$arg" done fi cd "$old_dir" } # Usage: make_files_1 ARG # Process one argument, ARG. make_files_1 () { if $change; then change=false if cd "$1"; then return else (exit 1); exit 1 fi fi case "$1" in -C) change=: ;; -C*) cd `expr "$1" : '-C\(.*\)' ` return ;; *) if test -d "$1"; then $mkdir_p "$JARTMP"/files/"$1" find "$1" | while read file; do if test -d "$file"; then $mkdir_p "$JARTMP"/files/"$file" else copy "$file" "$JARTMP"/files fi done else copy "$1" "$JARTMP"/files fi ;; esac cd "$old_dir" } # Same as "jar tf $1". jar_list () { $UNZIP -l "$1" | \ sed '1,/^ ----/d;/^ ----/,$d;s/^ *[0-9]* ..-..-.. ..:.. //' } # Same as "jar tvf $1". jar_list_verbose () { $UNZIP -l "$1" | \ @AWK@ 'BEGIN { yes = 0 } /^ ----/ { yes = !yes; next } yes { size=$1 split ($2, d, "-") split ($3, t, ":") d[3] += (d[3] < 80) ? 2000 : 1900 timestamp=d[3] " " d[1] " " d[2] " " t[1] " " t[2] " 00" gsub (/^ *[0-9]* ..-..-.. ..:.. /, "") printf "%6d %s %s\n", size, strftime ("%a %b %d %H:%M:%S %Z %Y", mktime (timestamp)), $0 }' } # mkdir -p emulation based on the mkinstalldirs script. func_mkdir_p () { for file do case $file in /*) pathcomp=/ ;; *) pathcomp= ;; esac oIFS=$IFS IFS=/ set fnord $file shift IFS=$oIFS errstatus=0 for d do test "x$d" = x && continue pathcomp=$pathcomp$d case $pathcomp in -*) pathcomp=./$pathcomp ;; esac if test ! -d "$pathcomp"; then mkdir "$pathcomp" || lasterr=$? test -d "$pathcomp" || errstatus=$lasterr fi pathcomp=$pathcomp/ done done return "$errstatus" } # Detect mkdir -p # On NextStep and OpenStep, the `mkdir' command does not # recognize any option. It will interpret all options as # directories to create, and then abort because `.' already # exists. if mkdir -p --version . >/dev/null 2>&1 && test ! -d ./--version; then mkdir_p='mkdir -p' else mkdir_p='func_mkdir_p' test -d ./-p && rmdir ./-p test -d ./--version && rmdir ./--version fi # Process the first command line option. case "$1" in -*) commands=`echo X"$1" | sed 's/^X-//' ` ;; *) commands="$1" esac shift # Operation to perform on the JAR file mode=unknown # First -C option on the command line cur_dir=. # Base directory for -C options old_dir=`pwd` # JAR file to operate on jarfile= # default for no {m,M} option, user for "m" option, none for "M" option manifest_kind=default # "-0" if the "0" option was given store= # true if the "v" option was given verbose=false # true if the non-standard "@" option was given process_response_files=false # An exec command if we need to redirect the zip/unzip commands' output out_redirect=: while test -n "$commands"; do # Process a letter at a time command=`expr "$commands" : '\(.\)'` commands=`expr "$commands" : '.\(.*\)'` case "$command" in c) set_var mode create ;; t) set_var mode list ;; x) set_var mode extract ;; u) set_var mode update ;; f) test $# = 0 && usage # Multiple "f" options are accepted by Sun's JAR tool. jarfile="$1" test -z "$jarfile" && usage shift ;; m) test $# = 0 && usage # Multiple "m" options are accepted by Sun's JAR tool, but # M always overrides m. test "$manifest_kind" = default && manifest_kind=user manifest_file="$1" test -z "$manifest_file" && usage shift ;; 0) store=-0 ;; v) verbose=: ;; i) # Not yet implemented, and probably never will. ;; M) manifest_kind=none ;; C) test $# = 0 && usage cur_dir="$1" shift ;; @) process_response_files=: ;; *) usage ;; esac done set -e case "X$jarfile" in X) # Work on stdin/stdout. Messages go to stderr, and if we need an input # JAR file we save it temporarily in the temporary directory. make_tmp $mkdir_p "$JARTMP"/out jarfile="$JARTMP"/out/tmp-stdin.jar out_redirect='exec >&2' case $mode in update|extract|list) if $process_response_files && test $# = 0; then error Cannot use stdin for response file. fi cat > "$JARTMP"/out/tmp-stdin.jar ;; esac ;; X*/*) # Make an absolute path. dir=`dirname "$jarfile"` jarfile=`cd $dir && pwd`/`basename "$jarfile"` ;; X*) # Make an absolute path from a filename in the current directory. jarfile=`pwd`/`basename "$jarfile"` ;; esac # Perform a -C option if given right away. cd "$cur_dir" case $mode in unknown) usage ;; extract) make_tmp # Extract the list of files in the JAR file jar_list "$jarfile" > "$JARTMP"/list # If there are files on the command line, expand directories and skip -C # command line arguments for arg do if $skip; then skip=false continue fi case "$arg" in -C) skip=: ;; -C*) ;; *) escaped=`echo "X$arg" | sed 's/^X//; s/[].[^$\\*]/\\\\&/g' ` grep "^$escaped/" "$JARTMP"/list >> "$JARTMP"/chosen || : grep "^$escaped\$" "$JARTMP"/list >> "$JARTMP"/chosen || : esac done test -f "$JARTMP"/chosen || cp "$JARTMP"/list "$JARTMP"/chosen # Really execute unzip if $verbose; then sort < "$JARTMP"/chosen | uniq | xargs $UNZIP -o "$jarfile" | \ sed -ne 's/^ creating/ created/p' -e 's/^ inflating/extracted/p' else sort < "$JARTMP"/chosen | uniq | xargs $UNZIP -o "$jarfile" > /dev/null fi ;; create) make_tmp $mkdir_p "$JARTMP"/out $mkdir_p "$JARTMP"/files # Do not overwrite the JAR file if something goes wrong tmp_jarfile="$JARTMP"/out/`basename "$jarfile"` # Prepare the files in the temporary directory. This is necessary to # support -C and still save relative paths in the JAR file. make_files ${1+"$@"} if test $manifest_kind != none; then make_manifest "$JARTMP"/files/META-INF/MANIFEST.MF $manifest_kind "$manifest_file" fi # Really execute zip if $verbose; then (eval $out_redirect; cd "$JARTMP"/files && $ZIP -rv "$tmp_jarfile" $store .) else (cd "$JARTMP/files" && $ZIP -r "$tmp_jarfile" $store . > /dev/null) fi test "$jarfile" = "$tmp_jarfile" || mv "$tmp_jarfile" "$jarfile" ;; update) make_tmp $mkdir_p "$JARTMP"/files make_files ${1+"$@"} # Same as above, but zip takes care of not overwriting the file case $manifest_kind in none) $verbose && (eval $out_redirect; echo removing manifest) $ZIP -d "$jarfile" META-INF/MANIFEST.MF > /dev/null 2>&1 || : ;; *) make_manifest "$JARTMP"/files/META-INF/MANIFEST.MF $manifest_kind "$manifest_file" ;; esac if $verbose; then (eval $out_redirect; cd "$JARTMP"/files && $ZIP -ruv "$jarfile" $store .) else (cd "$JARTMP"/files && $ZIP -ru "$jarfile" $store . > /dev/null) fi ;; list) # Everything's done in the functions if $verbose; then jar_list_verbose "$jarfile" else jar_list "$jarfile" fi ;; esac if test "$out_redirect" != :; then # Cat back to stdout if necessary case $mode in create|update) cat "$JARTMP"/out/tmp-stdin.jar ;; esac fi exit 0