jar.in 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524
  1. #! @SHELL@
  2. # Copyright (C) 2006 Free Software Foundation
  3. # Written by Paolo Bonzini.
  4. #
  5. # This program is free software; you can redistribute it and/or modify
  6. # it under the terms of the GNU General Public License as published
  7. # by the Free Software Foundation; either version 2 of the License,
  8. # or (at your option) any later version.
  9. #
  10. # This program is distributed in the hope that it will be useful, but
  11. # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  12. # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
  13. # for more details.
  14. #
  15. # You should have received a copy of the GNU General Public License along
  16. # with this program; if not, write to the Free Software Foundation, Inc.,
  17. # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  18. # POSIX and NLS nuisances, taken from autoconf.
  19. if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then
  20. emulate sh
  21. NULLCMD=:
  22. # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which
  23. # is contrary to our usage. Disable this feature.
  24. alias -g '${1+"$@"}'='"$@"'
  25. setopt NO_GLOB_SUBST
  26. else
  27. case `(set -o) 2>/dev/null` in *posix*) set -o posix;; esac
  28. fi
  29. BIN_SH=xpg4; export BIN_SH # for Tru64
  30. DUALCASE=1; export DUALCASE # for MKS sh
  31. if test "${LANG+set}" = set; then LANG=C; export LANG; fi
  32. if test "${LC_ALL+set}" = set; then LC_ALL=C; export LC_ALL; fi
  33. if test "${LC_MESSAGES+set}" = set; then LC_MESSAGES=C; export LC_MESSAGES; fi
  34. if test "${LC_CTYPE+set}" = set; then LC_CTYPE=C; export LC_CTYPE; fi
  35. # Also make sure CDPATH is empty, and IFS is space, tab, \n in that order.
  36. # Be careful to avoid that editors munge IFS
  37. (unset CDPATH) >/dev/null 2>&1 && unset CDPATH
  38. IFS=" "" ""
  39. "
  40. : ${TMPDIR=/tmp}
  41. : ${ZIP="@ZIP@"}
  42. : ${UNZIP="@UNZIP@"}
  43. progname="$0"
  44. # Emit a usage message and exit with error status 1
  45. usage () {
  46. cat >&2 <<EOF
  47. Usage: $0 {ctxu}[vfm0Mi@] [jar-file] [manifest-file] {[-C dir] files} ...
  48. Options:
  49. -c create new archive
  50. -t list table of contents for archive
  51. -x extract named (or all) files from archive
  52. -u update existing archive
  53. -v generate verbose output on standard output
  54. -f specify archive file name
  55. -m include manifest information from specified manifest file
  56. -0 store only; use no ZIP compression
  57. -M do not create a manifest file for the entries
  58. -i generate index information for the specified jar files
  59. -@ instead of {[-C dir] files} ... accept one or more response files,
  60. each containing one command-line argument
  61. -C change to the specified directory and include the following file
  62. If any file is a directory then it is processed recursively.
  63. The manifest file name and the archive file name needs to be specified
  64. in the same order the 'm' and 'f' flags are specified.
  65. Example 1: to archive two class files into an archive called classes.jar:
  66. jar cvf classes.jar Foo.class Bar.class
  67. Example 2: use an existing manifest file 'mymanifest' and archive all the
  68. files in the foo/ directory into 'classes.jar':
  69. jar cvfm classes.jar mymanifest -C foo/ .
  70. EOF
  71. (exit 1); exit 1
  72. }
  73. # Emit an error message and exit with error status 1
  74. error () {
  75. echo "$progname: $*" >&2
  76. (exit 1); exit 1
  77. }
  78. # Usage: copy SRC DEST
  79. # Copy file SRC to directory DEST, which is the staging area of the jar file.
  80. # Fail if it is already present or if it is not a regular file.
  81. copy () {
  82. if test -f "$1"; then
  83. # A simple optimization. Optimistically assuming that ln will work
  84. # cuts 60% of the run-time!
  85. if ln "$1" "$2"/"$1" > /dev/null 2>&1; then
  86. return 0
  87. fi
  88. if test -f "$2"/"$1"; then
  89. error "$1": Duplicate entry.
  90. fi
  91. dir=`dirname "$1"`
  92. $mkdir_p "$2"/"$dir"
  93. ln "$1" "$2"/"$1" > /dev/null 2>&1 || cp "$1" "$2"/"$1"
  94. elif test -e "$1"; then
  95. error "$1": Invalid file type.
  96. else
  97. error "$1": File not found.
  98. fi
  99. }
  100. # Make a temporary directory and store its name in the JARTMP variable.
  101. make_tmp () {
  102. test -n "$JARTMP" && return
  103. {
  104. JARTMP=`(umask 077 && mktemp -d "$TMPDIR/jarXXXXXX") 2>/dev/null` &&
  105. test -n "$JARTMP" && test -d "$JARTMP"
  106. } || {
  107. JARTMP=$TMPDIR/jar$$-$RANDOM
  108. (umask 077 && mkdir "$JARTMP")
  109. } || exit $?
  110. trap 'exit_status=$?
  111. if test -n "$JARTMP"; then rm -rf "$JARTMP"; fi
  112. exit $exit_status' 0
  113. }
  114. # Usage: make_manifest destfile kind [source-manifest]
  115. # Create a manifest file and store it in destfile. KIND can be "default",
  116. # or "user", in which case SOURCE-MANIFEST must be specified as well.
  117. make_manifest () {
  118. dir=`dirname "$1"`
  119. $mkdir_p "$dir"
  120. case $2 in
  121. default)
  122. cat > "$1" <<\EOF
  123. Manifest-Version: 1.0
  124. Created-By: @VERSION@
  125. EOF
  126. ;;
  127. user)
  128. cp "$3" "$1"
  129. ;;
  130. esac
  131. }
  132. # Usage: set_var var [value]
  133. # Exit with an error if set_var was already called for the same VAR. Else
  134. # set the variable VAR to the value VALUE (or the empty value if no parameter
  135. # is given).
  136. set_var () {
  137. if eval test x\$set_$1 = xset; then
  138. error Incompatible or repeated options.
  139. else
  140. eval $1=\$2
  141. eval set_$1=set
  142. fi
  143. }
  144. # Process the arguments, including -C options, and copy the whole tree
  145. # to $JARTMP/files so that zip can be invoked later from there.
  146. make_files () {
  147. change=false
  148. if $process_response_files; then
  149. if test $# = 0; then
  150. while read arg; do
  151. make_files_1 "$arg"
  152. done
  153. else
  154. for infile
  155. do
  156. exec 5<&0
  157. exec 0< $infile
  158. while read arg; do
  159. make_files_1 "$arg"
  160. done
  161. exec 0<&5
  162. exec 5<&-
  163. done
  164. fi
  165. else
  166. for arg
  167. do
  168. make_files_1 "$arg"
  169. done
  170. fi
  171. cd "$old_dir"
  172. }
  173. # Usage: make_files_1 ARG
  174. # Process one argument, ARG.
  175. make_files_1 () {
  176. if $change; then
  177. change=false
  178. if cd "$1"; then
  179. return
  180. else
  181. (exit 1); exit 1
  182. fi
  183. fi
  184. case "$1" in
  185. -C)
  186. change=:
  187. ;;
  188. -C*)
  189. cd `expr "$1" : '-C\(.*\)' `
  190. return
  191. ;;
  192. *)
  193. if test -d "$1"; then
  194. $mkdir_p "$JARTMP"/files/"$1"
  195. find "$1" | while read file; do
  196. if test -d "$file"; then
  197. $mkdir_p "$JARTMP"/files/"$file"
  198. else
  199. copy "$file" "$JARTMP"/files
  200. fi
  201. done
  202. else
  203. copy "$1" "$JARTMP"/files
  204. fi
  205. ;;
  206. esac
  207. cd "$old_dir"
  208. }
  209. # Same as "jar tf $1".
  210. jar_list () {
  211. $UNZIP -l "$1" | \
  212. sed '1,/^ ----/d;/^ ----/,$d;s/^ *[0-9]* ..-..-.. ..:.. //'
  213. }
  214. # Same as "jar tvf $1".
  215. jar_list_verbose () {
  216. $UNZIP -l "$1" | \
  217. @AWK@ 'BEGIN { yes = 0 }
  218. /^ ----/ { yes = !yes; next }
  219. yes {
  220. size=$1
  221. split ($2, d, "-")
  222. split ($3, t, ":")
  223. d[3] += (d[3] < 80) ? 2000 : 1900
  224. timestamp=d[3] " " d[1] " " d[2] " " t[1] " " t[2] " 00"
  225. gsub (/^ *[0-9]* ..-..-.. ..:.. /, "")
  226. printf "%6d %s %s\n", size, strftime ("%a %b %d %H:%M:%S %Z %Y", mktime (timestamp)), $0
  227. }'
  228. }
  229. # mkdir -p emulation based on the mkinstalldirs script.
  230. func_mkdir_p () {
  231. for file
  232. do
  233. case $file in
  234. /*) pathcomp=/ ;;
  235. *) pathcomp= ;;
  236. esac
  237. oIFS=$IFS
  238. IFS=/
  239. set fnord $file
  240. shift
  241. IFS=$oIFS
  242. errstatus=0
  243. for d
  244. do
  245. test "x$d" = x && continue
  246. pathcomp=$pathcomp$d
  247. case $pathcomp in
  248. -*) pathcomp=./$pathcomp ;;
  249. esac
  250. if test ! -d "$pathcomp"; then
  251. mkdir "$pathcomp" || lasterr=$?
  252. test -d "$pathcomp" || errstatus=$lasterr
  253. fi
  254. pathcomp=$pathcomp/
  255. done
  256. done
  257. return "$errstatus"
  258. }
  259. # Detect mkdir -p
  260. # On NextStep and OpenStep, the `mkdir' command does not
  261. # recognize any option. It will interpret all options as
  262. # directories to create, and then abort because `.' already
  263. # exists.
  264. if mkdir -p --version . >/dev/null 2>&1 && test ! -d ./--version; then
  265. mkdir_p='mkdir -p'
  266. else
  267. mkdir_p='func_mkdir_p'
  268. test -d ./-p && rmdir ./-p
  269. test -d ./--version && rmdir ./--version
  270. fi
  271. # Process the first command line option.
  272. case "$1" in
  273. -*) commands=`echo X"$1" | sed 's/^X-//' ` ;;
  274. *) commands="$1"
  275. esac
  276. shift
  277. # Operation to perform on the JAR file
  278. mode=unknown
  279. # First -C option on the command line
  280. cur_dir=.
  281. # Base directory for -C options
  282. old_dir=`pwd`
  283. # JAR file to operate on
  284. jarfile=
  285. # default for no {m,M} option, user for "m" option, none for "M" option
  286. manifest_kind=default
  287. # "-0" if the "0" option was given
  288. store=
  289. # true if the "v" option was given
  290. verbose=false
  291. # true if the non-standard "@" option was given
  292. process_response_files=false
  293. # An exec command if we need to redirect the zip/unzip commands' output
  294. out_redirect=:
  295. while test -n "$commands"; do
  296. # Process a letter at a time
  297. command=`expr "$commands" : '\(.\)'`
  298. commands=`expr "$commands" : '.\(.*\)'`
  299. case "$command" in
  300. c)
  301. set_var mode create
  302. ;;
  303. t)
  304. set_var mode list
  305. ;;
  306. x)
  307. set_var mode extract
  308. ;;
  309. u)
  310. set_var mode update
  311. ;;
  312. f)
  313. test $# = 0 && usage
  314. # Multiple "f" options are accepted by Sun's JAR tool.
  315. jarfile="$1"
  316. test -z "$jarfile" && usage
  317. shift
  318. ;;
  319. m)
  320. test $# = 0 && usage
  321. # Multiple "m" options are accepted by Sun's JAR tool, but
  322. # M always overrides m.
  323. test "$manifest_kind" = default && manifest_kind=user
  324. manifest_file="$1"
  325. test -z "$manifest_file" && usage
  326. shift
  327. ;;
  328. 0)
  329. store=-0
  330. ;;
  331. v)
  332. verbose=:
  333. ;;
  334. i)
  335. # Not yet implemented, and probably never will.
  336. ;;
  337. M)
  338. manifest_kind=none
  339. ;;
  340. C)
  341. test $# = 0 && usage
  342. cur_dir="$1"
  343. shift
  344. ;;
  345. @)
  346. process_response_files=: ;;
  347. *)
  348. usage ;;
  349. esac
  350. done
  351. set -e
  352. case "X$jarfile" in
  353. X)
  354. # Work on stdin/stdout. Messages go to stderr, and if we need an input
  355. # JAR file we save it temporarily in the temporary directory.
  356. make_tmp
  357. $mkdir_p "$JARTMP"/out
  358. jarfile="$JARTMP"/out/tmp-stdin.jar
  359. out_redirect='exec >&2'
  360. case $mode in
  361. update|extract|list)
  362. if $process_response_files && test $# = 0; then
  363. error Cannot use stdin for response file.
  364. fi
  365. cat > "$JARTMP"/out/tmp-stdin.jar
  366. ;;
  367. esac
  368. ;;
  369. X*/*)
  370. # Make an absolute path.
  371. dir=`dirname "$jarfile"`
  372. jarfile=`cd $dir && pwd`/`basename "$jarfile"`
  373. ;;
  374. X*)
  375. # Make an absolute path from a filename in the current directory.
  376. jarfile=`pwd`/`basename "$jarfile"`
  377. ;;
  378. esac
  379. # Perform a -C option if given right away.
  380. cd "$cur_dir"
  381. case $mode in
  382. unknown)
  383. usage
  384. ;;
  385. extract)
  386. make_tmp
  387. # Extract the list of files in the JAR file
  388. jar_list "$jarfile" > "$JARTMP"/list
  389. # If there are files on the command line, expand directories and skip -C
  390. # command line arguments
  391. for arg
  392. do
  393. if $skip; then
  394. skip=false
  395. continue
  396. fi
  397. case "$arg" in
  398. -C) skip=: ;;
  399. -C*) ;;
  400. *)
  401. escaped=`echo "X$arg" | sed 's/^X//; s/[].[^$\\*]/\\\\&/g' `
  402. grep "^$escaped/" "$JARTMP"/list >> "$JARTMP"/chosen || :
  403. grep "^$escaped\$" "$JARTMP"/list >> "$JARTMP"/chosen || :
  404. esac
  405. done
  406. test -f "$JARTMP"/chosen || cp "$JARTMP"/list "$JARTMP"/chosen
  407. # Really execute unzip
  408. if $verbose; then
  409. sort < "$JARTMP"/chosen | uniq | xargs $UNZIP -o "$jarfile" | \
  410. sed -ne 's/^ creating/ created/p' -e 's/^ inflating/extracted/p'
  411. else
  412. sort < "$JARTMP"/chosen | uniq | xargs $UNZIP -o "$jarfile" > /dev/null
  413. fi
  414. ;;
  415. create)
  416. make_tmp
  417. $mkdir_p "$JARTMP"/out
  418. $mkdir_p "$JARTMP"/files
  419. # Do not overwrite the JAR file if something goes wrong
  420. tmp_jarfile="$JARTMP"/out/`basename "$jarfile"`
  421. # Prepare the files in the temporary directory. This is necessary to
  422. # support -C and still save relative paths in the JAR file.
  423. make_files ${1+"$@"}
  424. if test $manifest_kind != none; then
  425. make_manifest "$JARTMP"/files/META-INF/MANIFEST.MF $manifest_kind "$manifest_file"
  426. fi
  427. # Really execute zip
  428. if $verbose; then
  429. (eval $out_redirect; cd "$JARTMP"/files && $ZIP -rv "$tmp_jarfile" $store .)
  430. else
  431. (cd "$JARTMP/files" && $ZIP -r "$tmp_jarfile" $store . > /dev/null)
  432. fi
  433. test "$jarfile" = "$tmp_jarfile" || mv "$tmp_jarfile" "$jarfile"
  434. ;;
  435. update)
  436. make_tmp
  437. $mkdir_p "$JARTMP"/files
  438. make_files ${1+"$@"}
  439. # Same as above, but zip takes care of not overwriting the file
  440. case $manifest_kind in
  441. none)
  442. $verbose && (eval $out_redirect; echo removing manifest)
  443. $ZIP -d "$jarfile" META-INF/MANIFEST.MF > /dev/null 2>&1 || :
  444. ;;
  445. *)
  446. make_manifest "$JARTMP"/files/META-INF/MANIFEST.MF $manifest_kind "$manifest_file"
  447. ;;
  448. esac
  449. if $verbose; then
  450. (eval $out_redirect; cd "$JARTMP"/files && $ZIP -ruv "$jarfile" $store .)
  451. else
  452. (cd "$JARTMP"/files && $ZIP -ru "$jarfile" $store . > /dev/null)
  453. fi
  454. ;;
  455. list)
  456. # Everything's done in the functions
  457. if $verbose; then
  458. jar_list_verbose "$jarfile"
  459. else
  460. jar_list "$jarfile"
  461. fi ;;
  462. esac
  463. if test "$out_redirect" != :; then
  464. # Cat back to stdout if necessary
  465. case $mode in
  466. create|update) cat "$JARTMP"/out/tmp-stdin.jar ;;
  467. esac
  468. fi
  469. exit 0