| #! @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 <<EOF |
| Usage: $0 {ctxu}[vfm0Mi@] [jar-file] [manifest-file] {[-C dir] files} ... |
| Options: |
| -c create new archive |
| -t list table of contents for archive |
| -x extract named (or all) files from archive |
| -u update existing archive |
| -v generate verbose output on standard output |
| -f specify archive file name |
| -m include manifest information from specified manifest file |
| -0 store only; use no ZIP compression |
| -M do not create a manifest file for the entries |
| -i generate index information for the specified jar files |
| -@ instead of {[-C dir] files} ... accept one or more response files, |
| each containing one command-line argument |
| -C change to the specified directory and include the following file |
| If any file is a directory then it is processed recursively. |
| The manifest file name and the archive file name needs to be specified |
| in the same order the 'm' and 'f' flags are specified. |
| |
| Example 1: to archive two class files into an archive called classes.jar: |
| jar cvf classes.jar Foo.class Bar.class |
| Example 2: use an existing manifest file 'mymanifest' and archive all the |
| files in the foo/ directory into 'classes.jar': |
| jar cvfm classes.jar mymanifest -C foo/ . |
| |
| EOF |
| (exit 1); exit 1 |
| } |
| |
| # Emit an error message and exit with error status 1 |
| error () { |
| echo "$progname: $*" >&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 |