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]

Re: [RFT/RFA] bashjar patch


Thanks for the review Ralf!
Be encouraged to pick the AS_BOURNE_COMPATIBLE contents from
Autoconf-2.59c (which contain a fix for the OpenBSD and OSF shells).
I am!
+progname="$0"
Will the script ever be invoked as $shell $path/to/jar? Then this can
be wrong.
This is used only for error messages, so no big deal.
Be encouraged to use the code documented in
info Autoconf "Limitations of Usual Tools"
You did encourage me to this as well.
+ trap 'rm -rf $JARTMP' EXIT
I think EXIT is not portable, but 0 is. Since with mktemp you'll still
need a trap or similar cleanup mechanism, and the exit status of the
script matters, you'll need to change all instances "exit N" to
(exit N); exit N
Ok, there were only a couple of occurrences, luckily.
+ exec 5<&0
+ exec 0< $infile
+ while read arg; do
+ make_files_1 "$arg"
+ done
+ exec 0<&5
I think it's ok to close 5 here:
exec 5<&-
Sure, I didn't know about the portability of this.
+# 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
+ }'
+}
I think this requires a non-traditional awk, and assumes that
AC_PROG_AWK will find one. (I don't know whether the install
documentation states this.)
It doesn't. Any hint for a portable replacement of strftime, or can we live with it? In the meanwhile I replaced %+ with a more portable representation.
IFS is allowed to be unset at shell startup; when it is, everything is
fine, as Posix requires things to work as if IFS contained space, tab,
newline.  However, after this sequence, IFS is set but empty; in this
case, field splitting is turned off.  (Some ash versions exposae this.)

To fix, initialize IFS with space, tab, newline (in that order!) at
script startup.
Fixed, but do you have any hint for doing this without putting whitespace at the end of the line?
+ 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" | \
Just curious: is there a reason not to use sort -u (two instances)?
Is it portable or GNU only?

The attached patch was rebootstrapped and re-regtested on i686-pc-linux-gnu.

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.
	* Makefile.am (bin_SCRIPTS): New.
	* jar.in: New file.

Index: Makefile.am
===================================================================
--- Makefile.am	(revision 113241)
+++ Makefile.am	(working copy)
@@ -89,7 +89,9 @@ bin_SCRIPTS = addr2name.awk
 ## Compilers and compilation flags.
 ##
 
-GCJH = @GCJH@
+if BASH_JAR
+bin_SCRIPTS += scripts/jar
+endif
 
 ## 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=`pwd`/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,520 @@
+#! /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+"$[@]"}'='"$[@]"'
+  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.
+(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 -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 () {
+  test -n "$JARTMP" && return
+
+  {
+    JARTMP=`(umask 077 && mktemp -d "$TMPDIR/fooXXXXXX") 2>/dev/null` &&
+      test -n "$JARTMP" && test -d "$JARTMP"
+  } || {
+    JARTMP=$TMPDIR/foo$$-$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 () {
+  $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
+        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.
+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
+      if $skip; then
+        skip=false
+	continue
+      fi
+      case "$arg" in
+	-C) skip=: ;;
+	-C*) ;;
+	*)
+	  escaped=`echo "$arg" | sed -n 's/[][.^$\*]/\\&/' `
+	  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

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