This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[RFT/RFA] bashjar patch


Hello,

this is the patch to implement a jar tool as a shell script, fixed to implement -C as in Sun's jar tool. Bootstrapped/regtested i686-pc-linux-gnu, ok to apply when I come back on May 15th?

Testing is appreciated with shells other than bash.

Paolo
2006-04-04  Paolo Bonzini  <bonzini@gnu.org>

	* configure.ac (ZIP, UNZIP): New programs.
	(JAR): Fall back to bash script.  Generate it.
	(BASH_JAR): New conditional.
	* jar.in: New file.
	* Makefile.am (bin_SCRIPTS): Add JAR.
	(JAR): New, overriding default definition from Automake.

Index: Makefile.am
===================================================================
--- Makefile.am	(revision 113241)
+++ Makefile.am	(working copy)
@@ -89,7 +89,11 @@ bin_SCRIPTS = addr2name.awk
 ## Compilers and compilation flags.
 ##
 
-GCJH = @GCJH@
+if BASH_JAR
+bin_SCRIPTS += scripts/jar
+endif
+
+JAR := $(patsubst ./%, $(shell pwd)/%, @JAR@)
 
 ## The compiler with whatever flags we want for both -c and -C
 ## compiles.
Index: configure.ac
===================================================================
--- configure.ac	(revision 113241)
+++ configure.ac	(working copy)
@@ -116,9 +116,18 @@ AC_CHECK_TOOL(AS, as)
 AC_CHECK_TOOL(LD, ld)
 AC_CHECK_TOOL(AR, ar)
 AC_CHECK_TOOL(RANLIB, ranlib, :)
-AC_CHECK_PROGS(JAR, [jar fastjar], false)
-if test "$JAR" = false; then
-  AC_MSG_ERROR(jar program not found)
+AC_PROG_AWK
+AC_CHECK_PROGS([JAR], [jar fastjar], no)
+AC_PATH_PROG([ZIP], [zip], no)
+AC_PATH_PROG([UNZIP], [unzip], unzip)
+AM_CONDITIONAL(BASH_JAR, test "$JAR" = no)
+if test "$ZIP" = no; then
+  if test "$JAR" = no; then
+    AC_MSG_ERROR([cannot find neither zip nor jar, cannot continue])
+  fi
+else
+  # InfoZIP available, use the 'guaranteed' Bourne-shell JAR to build libjava
+  JAR='$(top_builddir)/scripts/jar'
 fi
 
 AC_PROG_INSTALL
@@ -1479,6 +1488,8 @@ include/Makefile
 testsuite/Makefile
 ])
 
+AC_CONFIG_FILES([scripts/jar], [chmod +x scripts/jar])
+
 AC_CONFIG_COMMANDS([default],
 [# Only add multilib support code if we just rebuilt top-level Makefile.
 case " $CONFIG_FILES " in
Index: scripts/jar.in
===================================================================
--- scripts/jar.in	(revision 0)
+++ scripts/jar.in	(revision 0)
@@ -0,0 +1,503 @@
+#! /bin/sh
+# 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+"$@"}'='"$@"'
+elif test -n "${BASH_VERSION+set}" && (set -o posix) >/dev/null 2>&1; then
+  set -o posix
+fi
+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
+
+: ${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
+}
+
+# Emit an error message and exit with error status 1
+error () {
+  echo "$progname: $*" >&2
+  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 -e "$2"/"$1"; then
+      error "$1": Duplicate entry.
+    fi
+    $mkdir_p "$2"/`dirname "$1"`
+    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 () {
+  if test -z "$JARTMP"; then
+    JARTMPSUFF=$$
+    test -z "$RANDOM" && RANDOM=7654
+    while :; do
+      JARTMP=/tmp/tmp-jar.$JARTMPSUFF
+      $mkdir_p $JARTMP 2>&1 && break
+      JARTMPSUFF=`expr \( $JARTMPSUFF + $RANDOM \) % 32768`
+    done
+
+    trap 'rm -rf $JARTMP' EXIT
+  fi
+}
+
+# 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 () {
+  $mkdir_p `dirname "$1"`
+  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
+      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
+    cd "$1" || exit 1
+    return
+  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[2] " " d[1] " " t[1] " " t[2] " 00"
+	   gsub (/^ *[0-9]*  ..-..-.. ..:..   /, "")
+	   printf "%6d %s %s\n", size, strftime ("%+", mktime (timestamp)), $0
+	 }'
+}
+
+# mkdir -p emulation based on the mkinstalldirs script.
+mkdir_p ()
+{
+  for file
+  do
+    case $file in
+      /*) pathcomp=/ ;;
+      *)  pathcomp= ;;
+    esac
+    oIFS=$IFS
+    IFS=/
+    set fnord $file
+    shift
+    IFS=$oIFS
+
+    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='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
+      $skip && skip=false && continue
+      case "$arg" in
+	-C) skip=: ;;
+	-C*) ;;
+	*)
+	  escaped=`echo "$arg" | sed -n 's/[][.^$\*]/\\&/' `
+	  grep -e "^list/" >> $JARTMP/chosen || :
+	  grep -e "^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 "$@"
+    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 "$@"
+
+    # 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

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]