#! /bin/sh

# Bootstrap this package from checked-out sources.

# Copyright (C) 2003-2008 Free Software Foundation, Inc.

# 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 3 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, see <http://www.gnu.org/licenses/>.

# Written by Paul Eggert.

nl='
'

# Ensure file names are sorted consistently across platforms.
LC_ALL=C
export LC_ALL

local_gl_dir=gl

# Temporary directory names.
bt='._bootmp'
bt_regex=`echo "$bt"| sed 's/\./[.]/g'`
bt2=${bt}2

usage() {
  echo >&2 "\
Usage: $0 [OPTION]...
Bootstrap this package from the checked-out sources.

Options:
 --gnulib-srcdir=DIRNAME  Specify the local directory where gnulib
                          sources reside.  Use this if you already
                          have gnulib sources on your machine, and
                          do not want to waste your bandwidth downloading
                          them again.
 --copy                   Copy files instead of creating symbolic links.
 --force                  Attempt to bootstrap even if the sources seem
                          not to have been checked out.
 --skip-po                Do not download po files.

If the file $0.conf exists in the same directory as this script, its
contents are read as shell variables to configure the bootstrap.

Running without arguments will suffice in most cases.
"
}

# Configuration.

# Name of the Makefile.am
gnulib_mk=gnulib.mk

# List of gnulib modules needed.
gnulib_modules=

# Any gnulib files needed that are not in modules.
gnulib_files=

# The command to download all .po files for a specified domain into
# a specified directory.  Fill in the first %s is the domain name, and
# the second with the destination directory.  Use rsync's -L and -r
# options because the latest/%s directory and the .po files within are
# all symlinks.
po_download_command_format=\
"rsync -Lrtvz 'translationproject.org::tp/latest/%s/' '%s'"

extract_package_name='
  /^AC_INIT(/{
     /.*,.*,.*, */{
       s///
       s/[][]//g
       s/)$//
       p
       q
     }
     s/AC_INIT(\[*//
     s/]*,.*//
     s/^GNU //
     y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/
     s/[^A-Za-z0-9_]/-/g
     p
  }
'
package=`sed -n "$extract_package_name" configure.ac` || exit
gnulib_name=lib$package

build_aux=build-aux
source_base=lib
m4_base=m4
doc_base=doc
tests_base=tests

# Extra files from gnulib, which override files from other sources.
gnulib_extra_files="
	$build_aux/install-sh
	$build_aux/missing
	$build_aux/mdate-sh
	$build_aux/texinfo.tex
	$build_aux/depcomp
	$build_aux/config.guess
	$build_aux/config.sub
	doc/INSTALL
"

# Additional gnulib-tool options to use.  Use "\newline" to break lines.
gnulib_tool_option_extras=

# Other locale categories that need message catalogs.
EXTRA_LOCALE_CATEGORIES=

# Additional xgettext options to use.  Use "\\\newline" to break lines.
XGETTEXT_OPTIONS='\\\
 --flag=_:1:pass-c-format\\\
 --flag=N_:1:pass-c-format\\\
 --flag=error:3:c-format --flag=error_at_line:5:c-format\\\
'

# Package bug report address for gettext files
MSGID_BUGS_ADDRESS=bug-$package@gnu.org

# Files we don't want to import.
excluded_files=

# File that should exist in the top directory of a checked out hierarchy,
# but not in a distribution tarball.
checkout_only_file=README-hacking

# Whether to use copies instead of symlinks.
copy=false

# Set this to '.cvsignore .gitignore' in bootstrap.conf if you want
# those files to be generated in directories like lib/, m4/, and po/.
# Or set it to 'auto' to make this script select which to use based
# on which version control system (if any) is used in the source directory.
vc_ignore=auto

# Override the default configuration, if necessary.
# Make sure that bootstrap.conf is sourced from the current directory
# if we were invoked as "sh bootstrap".
case "$0" in
  */*) test -r "$0.conf" && . "$0.conf" ;;
  *) test -r "$0.conf" && . ./"$0.conf" ;;
esac


if test "$vc_ignore" = auto; then
  vc_ignore=
  test -d .git && vc_ignore=.gitignore
  test -d CVS && vc_ignore="$vc_ignore .cvsignore"
fi

# Translate configuration into internal form.

# Parse options.

for option
do
  case $option in
  --help)
    usage
    exit;;
  --gnulib-srcdir=*)
    GNULIB_SRCDIR=`expr "X$option" : 'X--gnulib-srcdir=\(.*\)'`;;
  --skip-po)
    SKIP_PO=t;;
  --force)
    checkout_only_file=;;
  --copy)
    copy=true;;
  *)
    echo >&2 "$0: $option: unknown option"
    exit 1;;
  esac
done

if test -n "$checkout_only_file" && test ! -r "$checkout_only_file"; then
  echo "$0: Bootstrapping from a non-checked-out distribution is risky." >&2
  exit 1
fi

# If $STR is not already on a line by itself in $FILE, insert it,
# sorting the new contents of the file and replacing $FILE with the result.
insert_sorted_if_absent() {
  file=$1
  str=$2
  test -f $file || touch $file
  echo "$str" | sort -u - $file | cmp -s - $file \
    || echo "$str" | sort -u - $file -o $file \
    || exit 1
}

# Die if there is no AC_CONFIG_AUX_DIR($build_aux) line in configure.ac.
found_aux_dir=no
grep '^[	 ]*AC_CONFIG_AUX_DIR(\['"$build_aux"'\])' configure.ac \
    >/dev/null && found_aux_dir=yes
grep '^[	 ]*AC_CONFIG_AUX_DIR('"$build_aux"')' configure.ac \
    >/dev/null && found_aux_dir=yes
if test $found_aux_dir = no; then
  echo "$0: expected line not found in configure.ac. Add the following:" >&2
  echo "  AC_CONFIG_AUX_DIR([$build_aux])" >&2
  exit 1
fi

# If $build_aux doesn't exist, create it now, otherwise some bits
# below will malfunction.  If creating it, also mark it as ignored.
if test ! -d $build_aux; then
  mkdir $build_aux
  for dot_ig in x $vc_ignore; do
    test $dot_ig = x && continue
    insert_sorted_if_absent $dot_ig $build_aux
  done
fi

echo "$0: Bootstrapping from checked-out $package sources..."

# See if we can use gnulib's git-merge-changelog merge driver.
if test -d .git && (git --version) >/dev/null 2>/dev/null ; then
  if git config merge.merge-changelog.driver >/dev/null ; then
    :
  elif (git-merge-changelog --version) >/dev/null 2>/dev/null ; then
    echo "initializing git-merge-changelog driver"
    git config merge.merge-changelog.name 'GNU-style ChangeLog merge driver'
    git config merge.merge-changelog.driver 'git-merge-changelog %O %A %B'
  else
    echo "consider installing git-merge-changelog from gnulib"
  fi
fi


cleanup_gnulib() {
  status=$?
  rm -fr gnulib
  exit $status
}

git_modules_config () {
  test -f .gitmodules && git config --file .gitmodules "$@"
}

# Get gnulib files.

case ${GNULIB_SRCDIR--} in
-)
  if git_modules_config submodule.gnulib.url >/dev/null; then
    echo "$0: getting gnulib files..."
    git submodule init || exit $?
    git submodule update || exit $?

  elif [ ! -d gnulib ]; then
    echo "$0: getting gnulib files..."

    trap cleanup_gnulib 1 2 13 15

    git clone --depth 2 git://git.sv.gnu.org/gnulib ||
      cleanup_gnulib

    trap - 1 2 13 15
  fi
  GNULIB_SRCDIR=gnulib
  ;;
*)
  # Redirect the gnulib submodule to the directory on the command line
  # if possible.
  if test -d "$GNULIB_SRCDIR"/.git && \
	git_modules_config submodule.gnulib.url >/dev/null; then
    git submodule init
    GNULIB_SRCDIR=`cd $GNULIB_SRCDIR && pwd`
    git config --replace-all submodule.gnulib.url $GNULIB_SRCDIR
    echo "$0: getting gnulib files..."
    git submodule update || exit $?
    GNULIB_SRCDIR=gnulib
  fi
  ;;
esac

gnulib_tool=$GNULIB_SRCDIR/gnulib-tool
<$gnulib_tool || exit

# Get translations.

download_po_files() {
  subdir=$1
  domain=$2
  echo "$0: getting translations into $subdir for $domain..."
  cmd=`printf "$po_download_command_format" "$domain" "$subdir"`
  eval "$cmd"
}

# Download .po files to $po_dir/.reference and copy only the new
# or modified ones into $po_dir.  Also update $po_dir/LINGUAS.
update_po_files() {
  # Directory containing primary .po files.
  # Overwrite them only when we're sure a .po file is new.
  po_dir=$1
  domain=$2

  # Download *.po files into this dir.
  # Usually contains *.s1 checksum files.
  ref_po_dir="$po_dir/.reference"

  test -d $ref_po_dir || mkdir $ref_po_dir || return
  download_po_files $ref_po_dir $domain \
    && ls "$ref_po_dir"/*.po 2>/dev/null |
      sed 's|.*/||; s|\.po$||' > "$po_dir/LINGUAS"

  langs=`cd $ref_po_dir && echo *.po|sed 's/\.po//g'`
  test "$langs" = '*' && langs=x
  for po in $langs; do
    case $po in x) continue;; esac
    new_po="$ref_po_dir/$po.po"
    cksum_file="$ref_po_dir/$po.s1"
    if ! test -f "$cksum_file" ||
	! test -f "$po_dir/$po.po" ||
	! sha1sum -c --status "$cksum_file" < "$new_po" > /dev/null; then
      echo "updated $po_dir/$po.po..."
      cp "$new_po" "$po_dir/$po.po" && sha1sum < "$new_po" > "$cksum_file"
    fi
  done
}

case $SKIP_PO in
'')
  if test -d po; then
    update_po_files po $package || exit
  fi

  if test -d runtime-po; then
    update_po_files runtime-po $package-runtime || exit
  fi;;
esac

symlink_to_dir()
{
  src=$1/$2
  dst=${3-$2}

  test -f "$src" && {

    # If the destination directory doesn't exist, create it.
    # This is required at least for "lib/uniwidth/cjk.h".
    dst_dir=`dirname "$dst"`
    if ! test -d "$dst_dir"; then
      mkdir -p "$dst_dir"

      # If we've just created a directory like lib/uniwidth,
      # tell version control system(s) it's ignorable.
      # FIXME: for now, this does only one level
      parent=`dirname "$dst_dir"`
      for dot_ig in x $vc_ignore; do
	test $dot_ig = x && continue
	ig=$parent/$dot_ig
	insert_sorted_if_absent $ig `echo "$dst_dir"|sed 's,.*/,,'`
      done
    fi

    if $copy; then
      {
	test ! -h "$dst" || {
	  echo "$0: rm -f $dst" &&
	  rm -f "$dst"
	}
      } &&
      test -f "$dst" &&
      cmp -s "$src" "$dst" || {
	echo "$0: cp -fp $src $dst" &&
	cp -fp "$src" "$dst"
      }
    else
      test -h "$dst" &&
      src_ls=`ls -diL "$src" 2>/dev/null` && set $src_ls && src_i=$1 &&
      dst_ls=`ls -diL "$dst" 2>/dev/null` && set $dst_ls && dst_i=$1 &&
      test "$src_i" = "$dst_i" || {
	dot_dots=
	case $src in
	/*) ;;
	*)
	  case /$dst/ in
	  *//* | */../* | */./* | /*/*/*/*/*/)
	     echo >&2 "$0: invalid symlink calculation: $src -> $dst"
	     exit 1;;
	  /*/*/*/*/)	dot_dots=../../../;;
	  /*/*/*/)	dot_dots=../../;;
	  /*/*/)	dot_dots=../;;
	  esac;;
	esac

	echo "$0: ln -fs $dot_dots$src $dst" &&
	ln -fs "$dot_dots$src" "$dst"
      }
    fi
  }
}

cp_mark_as_generated()
{
  cp_src=$1
  cp_dst=$2

  if cmp -s "$cp_src" "$GNULIB_SRCDIR/$cp_dst"; then
    symlink_to_dir "$GNULIB_SRCDIR" "$cp_dst"
  elif cmp -s "$cp_src" "$local_gl_dir/$cp_dst"; then
    symlink_to_dir $local_gl_dir "$cp_dst"
  else
    case $cp_dst in
      *.[ch])             c1='/* '; c2=' */';;
      *.texi)             c1='@c '; c2=     ;;
      *.m4|*/Make*|Make*) c1='# ' ; c2=     ;;
      *)                  c1=     ; c2=     ;;
    esac

    # If the destination directory doesn't exist, create it.
    # This is required at least for "lib/uniwidth/cjk.h".
    dst_dir=`dirname "$cp_dst"`
    test -d "$dst_dir" || mkdir -p "$dst_dir"

    if test -z "$c1"; then
      cmp -s "$cp_src" "$cp_dst" || {
	# Copy the file first to get proper permissions if it
	# doesn't already exist.  Then overwrite the copy.
	echo "$0: cp -f $cp_src $cp_dst" &&
	rm -f "$cp_dst" &&
	cp "$cp_src" "$cp_dst-t" &&
	sed "s!$bt_regex/!!g" "$cp_src" > "$cp_dst-t" &&
	mv -f "$cp_dst-t" "$cp_dst"
      }
    else
      # Copy the file first to get proper permissions if it
      # doesn't already exist.  Then overwrite the copy.
      cp "$cp_src" "$cp_dst-t" &&
      (
	echo "$c1-*- buffer-read-only: t -*- vi: set ro:$c2" &&
	echo "${c1}DO NOT EDIT! GENERATED AUTOMATICALLY!$c2" &&
	sed "s!$bt_regex/!!g" "$cp_src"
      ) > $cp_dst-t &&
      if cmp -s "$cp_dst-t" "$cp_dst"; then
	rm -f "$cp_dst-t"
      else
	echo "$0: cp $cp_src $cp_dst # with edits" &&
	mv -f "$cp_dst-t" "$cp_dst"
      fi
    fi
  fi
}

version_controlled_file() {
  dir=$1
  file=$2
  found=no
  if test -d CVS; then
    grep -F "/$file/" $dir/CVS/Entries 2>/dev/null |
	     grep '^/[^/]*/[0-9]' > /dev/null && found=yes
  elif test -d .git; then
    git rm -n "$dir/$file" > /dev/null 2>&1 && found=yes
  elif test -d .svn; then
    svn log -r HEAD "$dir/$file" > /dev/null 2>&1 && found=yes
  else
    echo "$0: no version control for $dir/$file?" >&2
  fi
  test $found = yes
}

slurp() {
  for dir in . `(cd $1 && find * -type d -print)`; do
    copied=
    sep=
    for file in `ls -a $1/$dir`; do
      case $file in
      .|..) continue;;
      .*) continue;; # FIXME: should all file names starting with "." be ignored?
      esac
      test -d $1/$dir/$file && continue
      for excluded_file in $excluded_files; do
	test "$dir/$file" = "$excluded_file" && continue 2
      done
      if test $file = Makefile.am; then
        copied=$copied${sep}$gnulib_mk; sep=$nl
	remove_intl='/^[^#].*\/intl/s/^/#/;'"s!$bt_regex/!!g"
        sed "$remove_intl" $1/$dir/$file | cmp -s - $dir/$gnulib_mk || {
	  echo "$0: Copying $1/$dir/$file to $dir/$gnulib_mk ..." &&
	  rm -f $dir/$gnulib_mk &&
	  sed "$remove_intl" $1/$dir/$file >$dir/$gnulib_mk
	}
      elif { test "${2+set}" = set && test -r $2/$dir/$file; } ||
	   version_controlled_file $dir $file; then
	echo "$0: $dir/$file overrides $1/$dir/$file"
      else
	copied=$copied$sep$file; sep=$nl
	if test $file = gettext.m4; then
	  echo "$0: patching m4/gettext.m4 to remove need for intl/* ..."
	  rm -f $dir/$file
	  sed '
	    /^AC_DEFUN(\[AM_INTL_SUBDIR],/,/^]/c\
	      AC_DEFUN([AM_INTL_SUBDIR], [
	    /^AC_DEFUN(\[gt_INTL_SUBDIR_CORE],/,/^]/c\
	      AC_DEFUN([gt_INTL_SUBDIR_CORE], [])
	    $a\
	      AC_DEFUN([gl_LOCK_EARLY], [])
	  ' $1/$dir/$file >$dir/$file
	else
	  cp_mark_as_generated $1/$dir/$file $dir/$file
	fi
      fi || exit
    done

    for dot_ig in x $vc_ignore; do
      test $dot_ig = x && continue
      ig=$dir/$dot_ig
      if test -n "$copied"; then
	insert_sorted_if_absent $ig "$copied"
	# If an ignored file name ends with .in.h, then also add
	# the name with just ".h".  Many gnulib headers are generated,
	# e.g., stdint.in.h -> stdint.h, dirent.in.h ->..., etc.
	# Likewise for .gperf -> .h, .y -> .c, and .sin -> .sed
	f=`echo "$copied"|sed 's/\.in\.h$/.h/;s/\.sin$/.sed/;s/\.y$/.c/;s/\.gperf$/.h/'`
	insert_sorted_if_absent $ig "$f"

	# For files like sys_stat.in.h and sys_time.in.h, record as
	# ignorable the directory we might eventually create: sys/.
	f=`echo "$copied"|sed 's/sys_.*\.in\.h$/sys/'`
	insert_sorted_if_absent $ig "$f"
      fi
    done
  done
}


# Create boot temporary directories to import from gnulib and gettext.
rm -fr $bt $bt2 &&
mkdir $bt $bt2 || exit

# Import from gnulib.

gnulib_tool_options="\
 --import\
 --no-changelog\
 --aux-dir $bt/$build_aux\
 --doc-base $bt/$doc_base\
 --lib $gnulib_name\
 --m4-base $bt/$m4_base/\
 --source-base $bt/$source_base/\
 --tests-base $bt/$tests_base\
 --local-dir $local_gl_dir\
 $gnulib_tool_option_extras\
"
echo "$0: $gnulib_tool $gnulib_tool_options --import ..."
$gnulib_tool $gnulib_tool_options --import $gnulib_modules &&
slurp $bt || exit

for file in $gnulib_files; do
  symlink_to_dir "$GNULIB_SRCDIR" $file || exit
done


# Import from gettext.
with_gettext=yes
grep '^[	 ]*AM_GNU_GETTEXT_VERSION(' configure.ac >/dev/null || \
    with_gettext=no

if test $with_gettext = yes; then
  echo "$0: (cd $bt2; autopoint) ..."
  cp configure.ac $bt2 &&
  (cd $bt2 && autopoint && rm configure.ac) &&
  slurp $bt2 $bt || exit
fi
rm -fr $bt $bt2 || exit

# Remove any dangling symlink matching "*.m4" or "*.[ch]" in some
# gnulib-populated directories.  Such .m4 files would cause aclocal to fail.
# The following requires GNU find 4.2.3 or newer.  Considering the usual
# portability constraints of this script, that may seem a very demanding
# requirement, but it should be ok.  Ignore any failure, which is fine,
# since this is only a convenience to help developers avoid the relatively
# unusual case in which a symlinked-to .m4 file is git-removed from gnulib
# between successive runs of this script.
find "$m4_base" "$source_base" \
  -depth \( -name '*.m4' -o -name '*.[ch]' \) \
  -type l -xtype l -delete > /dev/null 2>&1

# Reconfigure, getting other files.

for command in \
  libtool \
  'aclocal --force -I m4' \
  'autoconf --force' \
  'autoheader --force' \
  'automake --add-missing --copy --force-missing';
do
  if test "$command" = libtool; then
    grep '^[	 ]*AM_PROG_LIBTOOL\>' configure.ac >/dev/null ||
      continue
    command='libtoolize -c -f'
  fi
  echo "$0: $command ..."
  $command || exit
done


# Get some extra files from gnulib, overriding existing files.
for file in $gnulib_extra_files; do
  case $file in
  */INSTALL) dst=INSTALL;;
  build-aux/*) dst=$build_aux/`expr "$file" : 'build-aux/\(.*\)'`;;
  *) dst=$file;;
  esac
  symlink_to_dir "$GNULIB_SRCDIR" $file $dst || exit
done

if test $with_gettext = yes; then
  # Create gettext configuration.
  echo "$0: Creating po/Makevars from po/Makevars.template ..."
  rm -f po/Makevars
  sed '
    /^EXTRA_LOCALE_CATEGORIES *=/s/=.*/= '"$EXTRA_LOCALE_CATEGORIES"'/
    /^MSGID_BUGS_ADDRESS *=/s/=.*/= '"$MSGID_BUGS_ADDRESS"'/
    /^XGETTEXT_OPTIONS *=/{
      s/$/ \\/
      a\
	  '"$XGETTEXT_OPTIONS"' $${end_of_xgettext_options+}
    }
  ' po/Makevars.template >po/Makevars

  if test -d runtime-po; then
    # Similarly for runtime-po/Makevars, but not quite the same.
    rm -f runtime-po/Makevars
    sed '
      /^DOMAIN *=.*/s/=.*/= '"$package"'-runtime/
      /^subdir *=.*/s/=.*/= runtime-po/
      /^MSGID_BUGS_ADDRESS *=/s/=.*/= bug-'"$package"'@gnu.org/
      /^XGETTEXT_OPTIONS *=/{
	s/$/ \\/
	a\
	    '"$XGETTEXT_OPTIONS_RUNTIME"' $${end_of_xgettext_options+}
      }
    ' <po/Makevars.template >runtime-po/Makevars

    # Copy identical files from po to runtime-po.
    (cd po && cp -p Makefile.in.in *-quot *.header *.sed *.sin ../runtime-po)
  fi
fi

echo "$0: done.  Now you can run './configure'."