Subject: [PATCH 1/3] maint: use gnulib's maint.mk and support scripts release procedure.

From: "Gary V. Vaughan" <[email-masked]>
Date: Sun, 23 Oct 2011 23:03:07 +0700

All,

So, I went back on my word and decided to finish off the job I started
14 months ago when I wanted to beef up our bootstrap script, and ended
up instead writing a brand new one for gnulib (which I'm still working
on getting accepted upstream).  The batch of changesets I just pushed
are long past their 72-hour window (by about 9000 hours!), and I would
hate to see all the work I put into them (not to mention the last 3 days
of testing and fixing I just did to pull them into master and ensure
they are still working properly) go to waste.

It turns out that I quit libtool development a few patches too early,
and didn't quite finish the job of moving our infrastructure over to
the much better tested and wider deployed gnulib files last year.  These
last few patches get us most of the way there, so I feel better about
vastly reducing my libtool workload in the future.

By the end of this series, making a release still involves an awful lot
of waiting, but after passing the bevy of make distcheck variations
mandated in the README-release, is now a simple matter of:

  1. libltdl/config/do-release-commit-and-tag 2.4.4 stable
  3. make stable
  3. gnupload --to ftp.gnu.org:libtool libtool-2.4.4.tar.gz libtool-2.4.4.tar.xz
  4. libltd/config/gnu-web-doc-update
  5. git push origin master tag v2.4.4

Much more straight forward, and better tested than the old method which 
generally involved my sitting around all day running all the various
little steps we've been using until now.

I'll push in 72 hours, pending review comments that need addressing.

* NEWS: Updated.
* Makefile.maint: Removed.
* configure.ac (LASTRELEASE, lt_major, lt_minor, lt_micro, lt_alpha):
All removed. Makefile.maint was the only client.
* HACKING (Release Procedure): Removed.
* bootstrap.conf (gnulib_modules): Add announce-gen,
do-release-commit-and-tag, gendocs, gnu-web-doc-update, gnupload and
readme-release.
* cfg.mk (manual_title): Set it for web-manual rule.
(announcement_Cc_): Release announcement email addresses.
* Makefile.am (build_scripts): Add to EXTRA_DIST additional files
imported from gnulib for maint.mk release procedure.

Signed-off-by: Gary V. Vaughan <[email-masked]>
---
 .gitignore                                  |    2 +
 .prev-version                               |    1 +
 ChangeLog                                   |   15 +
 HACKING                                     |  273 +--------------
 Makefile.am                                 |   11 +-
 Makefile.maint                              |  206 -----------
 NEWS                                        |    6 +-
 bootstrap.conf                              |   58 +++-
 cfg.mk                                      |   10 +
 configure.ac                                |   52 +---
 doc/.gitignore                              |    1 +
 gl/build-aux/announce-gen.diff              |   39 ++
 gl/build-aux/do-release-commit-and-tag.diff |   22 ++
 gl/top/README-release.diff                  |   40 ++
 libltdl/config/.gitignore                   |    4 +
 libltdl/config/cvsu                         |  512 +++++++++++++++++++++++++++
 16 files changed, 713 insertions(+), 539 deletions(-)
 create mode 100644 .prev-version
 delete mode 100644 Makefile.maint
 create mode 100644 gl/build-aux/announce-gen.diff
 create mode 100644 gl/build-aux/do-release-commit-and-tag.diff
 create mode 100644 gl/top/README-release.diff
 create mode 100755 libltdl/config/cvsu

diff --git a/.gitignore b/.gitignore
index 87096df..ba06b16 100644
--- a/.gitignore
+++ b/.gitignore
@@ -36,6 +36,7 @@
 /COPYING
 /GNUmakefile
 /INSTALL
+/README-release
 /gnulib-local
 /libtoolize
 /libtoolize.in
@@ -67,3 +68,4 @@ testdir*
 testsuite
 testsuite.dir
 testsuite.log
+vc-diffs
diff --git a/.prev-version b/.prev-version
new file mode 100644
index 0000000..8e8299d
--- /dev/null
+++ b/.prev-version
@@ -0,0 +1 @@
+2.4.2
diff --git a/ChangeLog b/ChangeLog
index a3728f2..317be4d 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,18 @@
+2011-10-18  Gary V. Vaughan  <[email-masked]>
+
+	maint: use gnulib's maint.mk and support scripts release procedure.
+	* NEWS: Updated.
+	* Makefile.maint: Removed.
+	* configure.ac (LASTRELEASE, lt_major, lt_minor, lt_micro, lt_alpha):
+	All removed. Makefile.maint was the only client.
+	* HACKING (Release Procedure): Removed.
+	* bootstrap.conf (gnulib_modules): Add announce-gen,
+	do-release-commit-and-tag, gendocs, gnu-web-doc-update reademe-release
+	and gnupload.
+	* cfg.mk (manual_title): Set it for web-manual rule.
+	* Makefile.am (build_scripts): Add to EXTRA_DIST additional files
+	imported from gnulib for maint.mk release procedure.
+
 2011-10-19  Gary V. Vaughan  <[email-masked]>
 
 	maint: use gnulib's maintainer-makefile module.
diff --git a/HACKING b/HACKING
index b17de29..b438463 100644
--- a/HACKING
+++ b/HACKING
@@ -41,10 +41,9 @@ and is not part of a release distribution.
 	    + mdate-sh
 	    + missing
 	    + texinfo.tex
-  The ones that are important for a release can be udated with,
-  `make -fMakefile.maint fetch' (or `make -f../Makefile.maint fetch'
-  if you are running from a VPATH build directory, where `../' is the
-  relative path to the directory with `configure' in it).
+  The ones that are important for a release can be updated by ensuring
+  gnulib is up-to-date, and running `bootstrap` to recheck the links are
+  correct.
 
 * Changes other than bug fixes must be mentioned in NEWS
 
@@ -577,272 +576,6 @@ copy can be downloaded from  http://www.gnu.org/licenses/lgpl.html,
 or obtained by writing to the Free Software Foundation, Inc.,
 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 
-
-12. Release Procedure
-=====================
-
-* If you are a libtool maintainer, but have not yet registered your
-  gpg public key and (preferred) email address with the FSF, send an
-  email, preferably GPG-signed, to <[email-masked]> that includes
-  the following:
-
-    (a) name of package(s) that you are the maintainer for, and your
-        preferred email address.
-
-    (b) an ASCII armored copy of your GnuPG key, as an attachment.
-	("gpg --export -a YOUR_KEY_ID > mykey.asc" should give you
-	this.)
-
-  When you have received acknowledgement of your message, the proper GPG
-  keys will be registered on ftp-upload.gnu.org and only then will you be
-  authorized to upload files to the FSF ftp machines.
-
-* If you do not have access to the mailing list administrative interface,
-  approach the list owners for the password.  Be sure to check the lists
-  (esp. bug-libtool) for outstanding bug reports also in the list of
-  pending moderation requests.
-
-* Make sure you have wget and xz installed.
-
-* Make sure your locale is sane, e.g. by exporting LC_ALL=C.
-
-* Double check that serial number updates in public m4 files weren't forgotten
-  since last release (they should be updated in git along with commits that
-  require it so that users can work with git snapshots).
-
-* Update the LTDL_VERSION_INFO in libltdl/Makefile.inc for changes since
-  the last release.
-
-* Update the version number in configure.ac and libltdl/configure.ac.
-  See http://www.gnu.org/software/libtool/contribute.html for details of
-  the numbering scheme.
-
-* Update NEWS, ChangeLog.
-
-* Run ./bootstrap.
-
-* Run ./configure (or create a build directory first and run configure
-  from there, if you want to keep the build tree separate).
-
-* Run `make -fMakefile.maint fetch' (or `make -f../Makefile.maint fetch'
-  if you are running from a VPATH build directory, where `../' is the
-  relative path to the directory with `configure' in it), which will
-  fetch new versions of the files that are maintained outside of
-  libtool.
-
-* Run `make distcheck'
-  and `make distcheck DISTCHECK_CONFIGURE_FLAGS=--disable-ltdl-install'
-  and `make distcheck DISTCHECK_CONFIGURE_FLAGS=--program-prefix=g'
-  and `make distcheck DISTCHECK_CONFIGURE_FLAGS=--disable-shared'
-  and `make distcheck CC=g++'
-  If there are any problems, fix them and start again.
-
-* Run `git commit' from the source tree.
-
-* Run `make -fMakefile.maint git-dist' (or `make -f../Makefile.maint
-  git-dist' if you are running from a VPATH build directory, where `../'
-  is the relative path to the directory with `configure' in it), which
-  will build a release tarball (with `make distcheck'), tag the tree
-  with release-$(VERSION) and generate the gpg signature files.
-
-* Run 'make -f[../]Makefile.maint diffs' (pass
-  LASTRELEASE=maj.min[.mic[alpha]] if needed) to create diff files
-  between the previous release tarball and the new with detached gpg
-  signature files and clear signed directive files.
-
-* If not an alpha, generate with `make -f[../]Makefile.maint
-  web-manual'.
-
-* Upload release tarballs and diff files, plus their associated
-  detached gpg signature files and clear signed directive files to
-  ftp-upload.gnu.org.  If the upload is destined for ftp.gnu.org, then the
-  files should be placed in the /incoming/ftp directory.  If the upload is
-  an alpha release destined for alpha.gnu.org, then the files should be
-  placed in the /incoming/alpha directory.
-
-* Update version number in configure.ac and libltdl/configure.ac to next
-  alpha number.  See http://www.gnu.org/software/libtool/contribute.html
-  for details of the numbering scheme.
-
-* Update NEWS, ChangeLog.
-
-* Run `git commit'.
-
-* Run `git push --tags', to push the new changes and tags to origin.
-
-* Update the webpages, libtool.html will need to indicate the latest
-  release number.
-
-* If not an alpha, upload new manual pages you created earlier in
-  doc/manual using cvs to here:
-  <yourusername>@cvs.savannah.gnu.org:/webcvs/libtool
-
-* Write a release announcement, and post it to [email-masked]' and
-  [email-masked]' with the Reply-To header set to
-  [email-masked]'.  Stable releases should also be announced
-  on [email-masked]'.
-
-* Post a copy of your release announcement to savannah news:
-  https://savannah.gnu.org/news/submit.php?group=libtool
-  which will automatically propogate to http://planet.gnu.org.
-
-
-13. Alpha release note template
-===============================
-
-To: [email-masked], [email-masked]
-Reply-To: [email-masked]
-Subject: GNU Libtool @VERSION@ released (alpha release).
-
-The Libtool Team is pleased to announce alpha release @VERSION@ of GNU
-Libtool.
-
-GNU Libtool hides the complexity of using shared libraries behind a
-consistent, portable interface. GNU Libtool ships with GNU libltdl,
-which hides the complexity of loading dynamic runtime libraries
-(modules) behind a consistent, portable interface.
-
-Here are the compressed sources:
-
-  ftp://alpha.gnu.org/gnu/libtool/libtool-@VERSION@.tar.gz
-  ftp://alpha.gnu.org/gnu/libtool/libtool-@VERSION@.tar.bz2
-
-Here are the xdeltas and diffs against libtool-@PREV_RELEASE_VERSION_ON_THIS_BRANCH@:
-
-  ftp://alpha.gnu.org/gnu/libtool/libtool-@PREV_RELEASE_VERSION_ON_THIS_BRANCH@-@VERSION@.diff.gz
-  ftp://alpha.gnu.org/gnu/libtool/libtool-@PREV_RELEASE_VERSION_ON_THIS_BRANCH@-@VERSION@.xdelta
-
-Here are the gpg detached signatures:
-
-  ftp://alpha.gnu.org/gnu/libtool/libtool-@VERSION@.tar.gz.sig
-  ftp://alpha.gnu.org/gnu/libtool/libtool-@VERSION@.tar.bz2.sig
-  ftp://alpha.gnu.org/gnu/libtool/libtool-@PREV_RELEASE_VERSION_ON_THIS_BRANCH@-@VERSION@.diff.gz.sig
-  ftp://alpha.gnu.org/gnu/libtool/libtool-@PREV_RELEASE_VERSION_ON_THIS_BRANCH@-@VERSION@.xdelta.sig
-
-You should download the signature named after any tarball you download,
-and then verify its integrity with, for example:
-
-  gpg --verify libtool-@VERSION@.tar.gz.sig
-
-Here are the MD5 and SHA1 checksums:
-
-  @MD5SUM@ libtool-@VERSION@.tar.gz
-  @MD5SUM@ libtool-@VERSION@.tar.bz2
-  @MD5SUM@ libtool-@PREV_RELEASE_VERSION_ON_THIS_BRANCH@-@VERSION@.diff.gz
-  @MD5SUM@ libtool-@PREV_RELEASE_VERSION_ON_THIS_BRANCH@-@VERSION@.xdelta
-  @SHA1SUM@ libtool-@VERSION@.tar.gz
-  @SHA1SUM@ libtool-@VERSION@.tar.bz2
-  @SHA1SUM@ libtool-@PREV_RELEASE_VERSION_ON_THIS_BRANCH@-@VERSION@.diff.gz
-  @SHA1SUM@ libtool-@PREV_RELEASE_VERSION_ON_THIS_BRANCH@-@VERSION@.xdelta
-
-This release has @SUMMARY_OF_IMPROVEMENTS_SINCE_LAST_RELEASE_ON_THIS_BRANCH@.
-
-This release was bootstrapped with @BOOTSTRAP_TOOLS_WITH_VERSIONS@,
-but is useable with @COMPATIBLE_AUTOTOOL_VERSIONS@ in your own
-projects.
-
-Alternatively, you can fetch the unbootstrapped source code with
-git by using the following command:
-
-  $ git clone git://git.savannah.gnu.org/libtool.git
-  $ cd libtool
-  $ git checkout @GIT_RELEASE_TAG@
-
-You will then need to have recent (possibly as yet unreleased) versions
-of Automake and Autoconf installed to bootstrap the checked out
-sources yourself.
-
-New in @VERSION@: @RELEASE_DATE@
-
-  @EXCERPT_FROM_NEWS_FILE@
-
-Please report bugs to <[email-masked]>, along with the verbose
-output of any failed test groups, and the output from `./libtool --config.'
-The README file explains how to capture the verbose test output.
-
-
-
-14. Full release note template
-==============================
-
-To: [email-masked]
-Cc: [email-masked], [email-masked]
-Reply-To: [email-masked]
-Subject: GNU Libtool @VERSION@ released.
-
-The Libtool Team is pleased to announce the release of GNU Libtool
-@VERSION@.
-
-GNU Libtool hides the complexity of using shared libraries behind a
-consistent, portable interface. GNU Libtool ships with GNU libltdl,
-which hides the complexity of loading dynamic runtime libraries
-(modules) behind a consistent, portable interface.
-
-This release has @SUMMARY_OF_IMPROVEMENTS_SINCE_LAST_RELEASE_ON_THIS_BRANCH@.
-
-New in @VERSION@: @RELEASE_DATE@
-
-  @EXCERPT_FROM_NEWS_FILE@
-
-libtool-@VERSION@ is available now from ftp.gnu.org, along with
-diffs and xdeltas against libtool-@PREV_RELEASE_VERSION_ON_THIS_BRANCH@
-that are also available from ftp.gnu.org.  Please
-use a mirror to reduce stress on the main gnu machine:
-
-  http://www.gnu.org/order/ftp.html
-
-Here are the compressed sources:
-
-  ftp://ftp.gnu.org/gnu/libtool/libtool-@VERSION@.tar.gz
-  ftp://ftp.gnu.org/gnu/libtool/libtool-@VERSION@.tar.bz2
-
-Here are the xdeltas and diffs against libtool-@PREV_RELEASE_VERSION_ON_THIS_BRANCH@:
-
-  ftp://ftp.gnu.org/gnu/libtool/libtool-@PREV_RELEASE_VERSION_ON_THIS_BRANCH@-@VERSION@.diff.gz
-  ftp://ftp.gnu.org/gnu/libtool/libtool-@PREV_RELEASE_VERSION_ON_THIS_BRANCH@-@VERSION@.xdelta
-
-Here are the gpg detached signatures:
-
-  ftp://ftp.gnu.org/gnu/libtool/libtool-@VERSION@.tar.gz.sig
-  ftp://ftp.gnu.org/gnu/libtool/libtool-@VERSION@.tar.bz2.sig
-  ftp://ftp.gnu.org/gnu/libtool/libtool-@PREV_RELEASE_VERSION_ON_THIS_BRANCH@-@VERSION@.diff.gz.sig
-  ftp://ftp.gnu.org/gnu/libtool/libtool-@PREV_RELEASE_VERSION_ON_THIS_BRANCH@-@VERSION@.xdelta.sig
-
-You should download the signature named after any tarball you download,
-and then verify its integrity with, for example:
-
-  gpg --verify libtool-@VERSION@.tar.gz.sig
-
-Here are the MD5 and SHA1 checksums:
-
-  @MD5SUM@ libtool-@VERSION@.tar.gz
-  @MD5SUM@ libtool-@VERSION@.tar.bz2
-  @MD5SUM@ libtool-@PREV_RELEASE_VERSION_ON_THIS_BRANCH@-@VERSION@.diff.gz
-  @MD5SUM@ libtool-@PREV_RELEASE_VERSION_ON_THIS_BRANCH@-@VERSION@.xdelta
-  @SHA1SUM@ libtool-@VERSION@.tar.gz
-  @SHA1SUM@ libtool-@VERSION@.tar.bz2
-  @SHA1SUM@ libtool-@PREV_RELEASE_VERSION_ON_THIS_BRANCH@-@VERSION@.diff.gz
-  @SHA1SUM@ libtool-@PREV_RELEASE_VERSION_ON_THIS_BRANCH@-@VERSION@.xdelta
-
-This release was bootstrapped with @BOOTSTRAP_TOOLS_WITH_VERSIONS@,
-but is useable with @COMPATIBLE_AUTOTOOL_VERSIONS@ in your own
-projects.
-
-Alternatively, you can fetch the unbootstrapped source code with
-git by using the following command:
-
-  $ git clone git://git.savannah.gnu.org/libtool.git
-  $ cd libtool
-  $ git checkout @GIT_RELEASE_TAG@
-
-You will then need to have the latest release versions of Automake
-(@AUTOMAKE_VERSION@) and Autoconf (@AUTOCONF_VERSION@) installed to
-bootstrap the checked out sources yourself.
-
-Please report bugs to <[email-masked]>, along with the verbose
-output of any failed test groups, and the output from `./libtool --config.'
-The README file explains how to capture the verbose test output.
-
 -- 
   Copyright (C) 2004, 2005, 2006, 2007, 2008, 2010 Free Software
   Foundation, Inc.
diff --git a/Makefile.am b/Makefile.am
index 09b61fa..6ed3de5 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -73,7 +73,14 @@ libtoolize_m4sh	= $(srcdir)/libtoolize.m4sh
 ltmain_m4sh	= $(m4sh_dir)/ltmain.m4sh
 
 sh_files	= $(general_m4sh) $(getopt_m4sh)
-EXTRA_DIST     += bootstrap bootstrap.conf cfg.mk maint.mk $(aux_dir)/mkstamp \
+build_scripts	= $(aux_dir)/announce-gen $(aux_dir)/cvsu \
+		  $(aux_dir)/do-release-commit-and-tag \
+		  $(aux_dir)/gendocs.sh \
+		  $(aux_dir)/gnu-web-doc-update $(aux_dir)/gnupload \
+		  $(aux_dir)/mkstamp \
+		  $(aux_dir)/useless-if-before-free $(aux_dir)/vc-list-files
+
+EXTRA_DIST     += bootstrap bootstrap.conf $(build_scripts) cfg.mk maint.mk \
 		  $(sh_files) ChangeLog.1996 ChangeLog.1997 ChangeLog.1998 \
 		  ChangeLog.1999 ChangeLog.2000 ChangeLog.2001 ChangeLog.2002 \
 		  ChangeLog.2003 ChangeLog.2004 ChangeLog.2005 ChangeLog.2006 \
@@ -371,6 +378,8 @@ libtoolize_1	= $(doc_dir)/libtoolize.1
 notes_texi	= $(doc_dir)/notes.texi
 notes_txt	= $(doc_dir)/notes.txt
 
+EXTRA_DIST	+= $(doc_dir)/gendocs_template
+
 # A bug in automake 1.11.1 (at least) prevents us from using:
 #
 #   info_TEXINFOS	= $(doc_dir)/libtool.texi
diff --git a/Makefile.maint b/Makefile.maint
deleted file mode 100644
index 675e733..0000000
--- a/Makefile.maint
+++ /dev/null
@@ -1,206 +0,0 @@
-## Makefile.maint -- Makefile rules for libtool maintainers -*-Makefile-*-
-##
-##   Copyright (C) 2004, 2005, 2010 Free Software Foundation, Inc.
-##   Written by Scott James Remnant, 2004
-##
-##   This file is part of GNU Libtool.
-##
-## GNU Libtool 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.
-##
-## GNU Libtool 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 GNU Libtool; see the file COPYING.  If not, a copy
-## can be downloaded from http://www.gnu.org/licenses/gpl.html,
-## or obtained by writing to the Free ## Software Foundation, Inc.,
-## 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#####
-
-# Need various variables defined by configure, a lot easier to just
-# include the Makefile than figure out a way to put them in here too
-include Makefile
-Makefile:
-	@echo " *** Run maintainer rules from the build tree, with"
-	@echo " *** \`make -f../Makefile.maint' for example, where"
-	@echo " *** \`../' is the relative path back to the directory"
-	@echo " *** that contains the \`Makefile.maint'.  Alternatively,"
-	@echo " *** run \`./configure' in the source tree for an in"
-	@echo " *** tree build."
-	@exit 1
-
-TEXI2HTML = texi2html
-
-.PHONY: git-release
-git-release: version-check prev-tarball check-news fetch git-dist diffs web-manual
-	@tarname="$(PACKAGE)-$(VERSION).tar.gz"; \
-	xzname="$(PACKAGE)-$(VERSION).tar.xz"; \
-	diffname="$(PACKAGE)-$(LASTRELEASE)-$(VERSION).diff.gz"; \
-	echo " *** Upload $$tarname, $$tarname.sig,";\
-	echo " *** $$tarname.directive.asc, $$xzname,";\
-	echo " *** $$xzname.sig, $$xzname.directive.asc,";\
-	echo " *** $$diffname, $$diffname.sig";\
-	echo " ***  and $$diffname.directive.asc to either"; \
-	echo " *** /incoming/alpha or /incoming/ftp on ftp-upload.gnu.org."
-	echo " *** You might need to upload manual.html to webcvs/libtool."
-
-.PHONY: version-check
-version-check:
-	@case $(VERSION) in \
-	*[acegikmoqsuwy]) \
-	  echo "Version \`$(VERSION)' is not a releasable version, please read:"; \
-	  echo "    http://www.gnu.org/software/libtool/contribute.html"; \
-	  exit 1; \
-	  ;; \
-	esac
-
-GIT = git # set it to `:' to avoid git write operations
-
-.PHONY: check-commit
-check-commit:
-	@if (cd $(srcdir) && test -d .git && \
-	    $(GIT) status | grep 'modified:'); then \
-		echo "Cannot make git-dist before commit"; exit 1; else :; fi
-
-
-.PHONY: check-news
-check-news:
-## Make sure the NEWS file is up-to-date:
-	@if sed '1,2d;3q' $(srcdir)/NEWS | grep -e "$(VERSION)" >/dev/null; \
-	then :; \
-	else \
-	  echo "NEWS not updated; not releasing" 1>&2; \
-	  exit 1; \
-	fi
-
-## Program to use to fetch files.
-WGET = wget
-WGETSGO = $(WGET) 'http://savannah.gnu.org/cgi-bin/viewcvs/~checkout~'
-WGET_GIT = $(WGET) 'http://git.savannah.gnu.org/gitweb/?a=blob_plain;hb=HEAD;p='
-WGET_CGIT = $(WGET) 'http://git.savannah.gnu.org/cgit/config.git/plain'
-
-## Files that we fetch and which we compare against.
-## FIXME should be a lot more here
-FETCHFILES = \
-./INSTALL \
-$(aux_dir)/compile \
-$(aux_dir)/install-sh \
-$(aux_dir)/config.guess \
-$(aux_dir)/config.sub \
-$(aux_dir)/texinfo.tex
-
-## Fetch the latest versions of files we care about.
-.PHONY: fetch
-fetch:
-	rm -rf Fetchdir > /dev/null 2>&1
-	mkdir Fetchdir
-## If a get fails then that is a problem.
-	(cd Fetchdir && \
-	$(WGET_GIT)'gnulib.git;f=doc/INSTALL' -O INSTALL && \
-	$(WGET_GIT)'automake.git;f=lib/compile' -O compile && \
-	$(WGET_GIT)'automake.git;f=lib/install-sh' -O install-sh && \
-	$(WGET_CGIT)/config.guess -O config.guess && \
-	$(WGET_CGIT)/config.sub -O config.sub && \
-	$(WGETSGO)/texinfo/texinfo/doc/texinfo.tex -O texinfo.tex )
-## Don't exit after test because we want to give as many errors as
-## possible.
-	@stat=0; for file in $(FETCHFILES); do \
-	  fetchedfile=Fetchdir/`echo $$file | sed 's,.*/,,g'`; \
-	  if diff -u $(srcdir)/$$file $$fetchedfile \
-	    >>Fetchdir/update.patch 2>/dev/null; then :; \
-	  else \
-	    stat=1; \
-	    echo "Updating $(srcdir)/$$file..."; \
-	    cp $$fetchedfile $(srcdir)/$$file; \
-	  fi; \
-	done; \
-	test $$stat = 1 && \
-	  echo "See Fetchdir/update.patch for a log of the changes."; \
-	exit $$stat
-
-
-GPG = gpg # set it to `:' to avoid gpg operations
-
-.PHONY: git-dist
-git-dist: check-news check-commit
-## Build the distribution:
-	$(MAKE) distcheck
-## Finally, if everything was successful, tag the release
-	cd $(srcdir) \
-	  && $(GIT) tag -s "v$(VERSION)"
-## Generate signatures and directives for FSF ftp-upload:
-	for suffix in gz xz; do \
-	  ofile="$(PACKAGE)-$(VERSION).tar.$$suffix"; \
-	  $(GPG) --detach-sign $$ofile \
-	  && echo "version: 1.1" > $$ofile.directive \
-	  && echo "directory: libtool" >> $$ofile.directive \
-	  && echo "filename: $$ofile" >> $$ofile.directive \
-	  && $(GPG) --clearsign $$ofile.directive \
-	  && rm -f $$ofile.directive; \
-	done
-
-.PHONY: prev-tarball
-prev-tarball:
-## Make sure we have the previous release tarball in the tree.
-	@if test -z "$(LASTRELEASE)"; \
-		then echo "LASTRELEASE is not set"; exit 1; fi
-	@ofile="$(PACKAGE)-$(LASTRELEASE).tar.gz"; \
-	if test -f $$ofile; then :; \
-	else ofile="$(PACKAGE)-$(LASTRELEASE).tar.xz"; \
-          if test -f $$ofile; then :; \
-          else echo "Cannot make diffs without $$ofile"; exit 1; fi; fi
-
-.PHONY: new-tarball
-new-tarball:
-## Make sure we have the new release tarball in the tree.
-	@ofile="$(PACKAGE)-$(VERSION).tar.gz"; \
-	if test -f $$ofile; then :; \
-	else ofile="$(PACKAGE)-$(VERSION).tar.xz"; \
-          if test -f $$ofile; then :; \
-          else echo "Cannot make diffs without $$ofile"; exit 1; fi; fi
-
-DIFF = diff
-DIFF_OPTIONS = -ruNp
-
-.PHONY: diffs
-diffs: prev-tarball new-tarball
-## Unpack the tarballs somewhere to diff them
-	rm -rf delta-diff
-	mkdir delta-diff
-
-	cd delta-diff; \
-	ofile="../$(PACKAGE)-$(LASTRELEASE)-$(VERSION).diff.gz"; \
-	otar="../$(PACKAGE)-$(LASTRELEASE).tar"; \
-	ntar="../$(PACKAGE)-$(VERSION).tar"; \
-	test -f "$$otar.gz" && otar="$$otar.gz" && ounpack="gzip"; \
-	test -f "$$ntar.gz" && ntar="$$ntar.gz" && nunpack="gzip"; \
-	test -f "$$otar.xz" && otar="$$otar.xz" && ounpack="xz"; \
-	test -f "$$ntar.xz" && ntar="$$ntar.xz" && nunpack="xz"; \
-	$$ounpack -c -d "$$otar" | tar xf - \
-	&& $$nunpack -c -d "$$ntar" | tar xf - \
-	&& $(DIFF) $(DIFF_OPTIONS) \
-		$(PACKAGE)-$(LASTRELEASE) $(PACKAGE)-$(VERSION) \
-		| GZIP=$(GZIP_ENV) gzip -c > $$ofile \
-	&& $(GPG) --detach-sign $$ofile \
-	&& echo "version: 1.1" > $$ofile.directive \
-	&& echo "directory: libtool" >> $$ofile.directive \
-	&& echo "filename: $$ofile" |sed 's,: \.\./,: ,' >> $$ofile.directive \
-	&& $(GPG) --clearsign $$ofile.directive \
-	&& rm -f $$ofile.directive
-
-	rm -rf delta-diff
-
-.PHONY: web-manual
-web-manual:
-	cd $(srcdir)/doc; \
-	rm -f gendocs.sh* gendocs_template*; \
-	test -d manual && rm -rf manual; \
-	$(WGETSGO)'/texinfo/texinfo/util/gendocs.sh' && \
-	$(WGETSGO)'/texinfo/texinfo/util/gendocs_template' && \
-	chmod 755 gendocs.sh && \
-	./gendocs.sh --email [email-masked] libtool "GNU Libtool Manual"
diff --git a/NEWS b/NEWS
index c5533c5..699d340 100644
--- a/NEWS
+++ b/NEWS
@@ -1,10 +1,10 @@
 NEWS - list of user-visible changes between releases of GNU Libtool
 
-New in 2.4.4 201?-??-??: git version 2.4.3a, Libtool team:
+* Noteworthy changes in release ?.? (????-??-??) [?]
 
-* Bug fixes:
+* New features:
 
-  - Waiting for bug reports...
+  - Moved to gnulib release infrastructure.
 
 New in 2.4.2 2011-10-17: git version 2.4.1a, Libtool team:
 
diff --git a/bootstrap.conf b/bootstrap.conf
index 4650003..c06729d 100644
--- a/bootstrap.conf
+++ b/bootstrap.conf
@@ -1,6 +1,6 @@
-# bootstrap.conf (GNU Libtool) version 2011-10-19
+# bootstrap.conf (GNU Libtool) version 2011-10-20
 #
-# Copyright (C) 2010 Free Software Foundation, Inc.
+# Copyright (C) 2010, 2011 Free Software Foundation, Inc.
 # Written by Gary V. Vaughan, 2010
 
 # This is free software; see the source for copying conditions.  There is NO
@@ -60,7 +60,13 @@ gnulib_tool_options=$gnulib_tool_options"
 
 # gnulib modules used by this package.
 gnulib_modules='
+        announce-gen
+        do-release-commit-and-tag
+        gendocs
+        gnu-web-doc-update
+        gnupload
         maintainer-makefile
+        readme-release
 '
 
 # Extra gnulib files that are not in modules, which override files of
@@ -262,6 +268,18 @@ libtool_prep ()
 func_add_hook func_prep libtool_prep

+# libtool_add_libltdl_copying
+# ---------------------------
+# Use the canonical COPYING.LESSERv2 from gnulib.
+libtool_add_libltdl_copying ()
+{
+    $debug_cmd
+
+    func_gnulib_tool_copy_file doc/COPYING.LESSERv2 libltdl/COPYING.LIB
+}
+func_add_hook func_gnulib_tool libtool_add_libltdl_copying
+
+
 # libtool_build_prerequisites
 # ---------------------------
 # Libtool generates some files that are required before any autotools
@@ -317,19 +335,41 @@ libtool_build_prerequisites ()
     rm -f Makefile
     test 0 -eq "$status" ||exit $EXIT_FAILURE
 }
-func_add_hook func_prep libtool_build_prerequisites
+func_add_hook func_gnulib_tool libtool_build_prerequisites

-# libtool_add_libltdl_copying
-# ---------------------------
-# Use the canonical COPYING.LESSERv2 from gnulib.
-libtool_add_libltdl_copying ()
+# libtool_readme_release_package_substitutions
+# --------------------------------------------
+# Show our own package details instead of generic strings.
+libtool_readme_release_package_substitutions ()
 {
     $debug_cmd
 
-    func_gnulib_tool_copy_file doc/COPYING.LESSERv2 libltdl/COPYING.LIB
+    $require_build_aux
+    $require_package
+
+    readme=README-release
+
+    # Perform substitutions to a temporary file
+    test -f "$readme" \
+        || func_fatal error "Error: \`$readme' does not exist"
+
+    $SED -e "\
+        s,\@PACKAGE\@,$package,g
+        s,build-aux/,$build_aux/,
+    " "$readme" > "${readme}T"
+
+    # move-if-change ${readme}T $readme
+    if test -f "$readme" \
+        && func_cmp_s "${readme}T" "$readme"
+    then
+      rm -f "${readme}T"
+    else
+      rm -f "$readme"
+      mv "${readme}T" "$readme"
+    fi
 }
-func_add_hook func_gnulib_tool libtool_add_libltdl_copying
+func_add_hook func_fini libtool_readme_release_package_substitutions

 # libtool_fudge_timestamps
diff --git a/cfg.mk b/cfg.mk
index f2a712a..89cb014 100644
--- a/cfg.mk
+++ b/cfg.mk
@@ -27,6 +27,16 @@ _build-aux = libltdl/config
 # Set format of NEWS
 old_NEWS_hash := d41d8cd98f00b204e9800998ecf8427e
 
+manual_title = Portable Dynamic Shared Object Management
+
+# Set the release announcement email addresses, maint.mk will email the
+# translation-project instead of autotools-announce otherwise.
+ifeq ($(RELEASE_TYPE),stable)
+announcement_Cc_ = [email-masked]
+else
+announcement_Cc_ = [email-masked], $(PACKAGE_BUGREPORT)
+endif
+
 # Don't syntax check the mail subdirectory.
 VC_LIST_ALWAYS_EXCLUDE_REGEX = /mail/
 
diff --git a/configure.ac b/configure.ac
index 5f052b0..c51ec28 100644
--- a/configure.ac
+++ b/configure.ac
@@ -67,61 +67,13 @@ AC_SUBST([AUTOTEST], ['$(AUTOM4TE) --language=autotest'])
 ## Display a configure time version banner. ##
 ## ---------------------------------------- ##
 
-# Calculating the previous version is somewhat involved, so do it once
-# here, and SUBST the result for the maintainer release rules.  The
-# versioning scheme we use is described here:
-#	http://www.gnu.org/software/libtool/contribute.html
-
-# First we break the version number up into its constituent parts.
-lt_major=`echo "AC_PACKAGE_VERSION" | sed ['s,\..*$,,g']`
-lt_minor=`echo "AC_PACKAGE_VERSION" | sed ['s,^[0-9]*\.\([0-9]*\).*$,\1,']`
-lt_micro=`echo "AC_PACKAGE_VERSION" | sed ['s,^[0-9]*\.[0-9]*\(\.[0-9]*\).*$,\1,']`
-lt_alpha=`echo "AC_PACKAGE_VERSION" | sed ['s,^[0-9.]*,,']`
-
-test "$lt_minor" = "AC_PACKAGE_VERSION" && lt_minor=0
-test "$lt_micro" = "AC_PACKAGE_VERSION" && lt_micro=""
-
-# Then we try to work out what the release before this one would have been
-# numbered.  The only time we come unstuck is when this is the first release
-# from a stable branch (lt_micro=lt_alpha=""), so LASTRELEASE is the last
-# release from the old stable branch, and we don't know what version that
-# was, so leave it unset so that the Makefile can complain.
-case $lt_alpha in
-  [[ab]])
-    case $lt_micro in
-      [.[01]])
-	LASTRELEASE="$lt_major.$lt_minor" ;;
-      *)
-	LASTRELEASE="$lt_major.$lt_minor$lt_micro" ;;
-    esac
-    ;;
-  [[cegikmoqsuwy]])
-    LASTRELEASE=`echo "AC_PACKAGE_VERSION" | tr 'c-y' 'b-w'` ;;
-  [[dfhjlnprtvxz]])
-    LASTRELEASE=`echo "AC_PACKAGE_VERSION" | tr 'd-z' 'b-x'` ;;
-  *) # No lt_alpha component
-    case $lt_micro in
-      .0)
-	LASTRELEASE="" ;;
-      .1)
-        LASTRELEASE="$lt_major.$lt_minor" ;;
-      .*)
-	lt_micro_value=`echo $lt_micro | sed 's,^\.,,'`
-	LASTRELEASE="$lt_major.$lt_minor.`expr $lt_micro_value - 1`" ;;
-      *)
-	LASTRELEASE="" ;;
-    esac
-    ;;
-esac
-AC_SUBST([LASTRELEASE])
-
 # This is a sanity check so we can see which version is used in bug reports.
 # It is assumed that we only want to see the date extension for cvs libtool
 # versions (i.e. "odd" letters) and not actual alpha releases.
 TIMESTAMP=`${CONFIG_SHELL} ${ac_aux_dir}/mkstamp ${srcdir}`
 package_revision=`( set $TIMESTAMP; echo $1; )`
-case $lt_alpha in
-  ""|[[bdfhjlnprtvxz]])
+case $package_revision in
+  *[[bdfhjlnprtvxz]])
     TIMESTAMP=
     ;;
 esac
diff --git a/doc/.gitignore b/doc/.gitignore
index 8d60e81..2e7c6bf 100644
--- a/doc/.gitignore
+++ b/doc/.gitignore
@@ -2,5 +2,6 @@
 /*.html
 /fdl.texi
 /gendocs_template
+/manual
 /notes.txt
 /version.texi
diff --git a/gl/build-aux/announce-gen.diff b/gl/build-aux/announce-gen.diff
new file mode 100644
index 0000000..937918a
--- /dev/null
+++ b/gl/build-aux/announce-gen.diff
@@ -0,0 +1,39 @@
+--- gnulib/build-aux/announce-gen	2011-10-19 01:26:27.000000000 +0700
++++ gl/build-aux/announce-gen	2011-10-19 16:54:12.000000000 +0700
+@@ -102,7 +102,7 @@
+   my %res;
+   foreach my $f (@file)
+     {
+-      my $cmd = "du --human $f";
++      my $cmd = "du -h $f";
+       my $t = `$cmd`;
+       # FIXME-someday: give a better diagnostic, a la $PROCESS_STATUS
+       $@
+@@ -449,7 +449,14 @@
+ 
+ <\#secure method=pgpmime mode=sign>
+ 
+-FIXME: put comments here
++Libtoolers!
++
++The Libtool Team is pleased to announce the release of $package_name $curr_version.
++
++GNU Libtool hides the complexity of using shared libraries behind a
++consistent, portable interface. GNU Libtool ships with GNU libltdl, which
++hides the complexity of loading dynamic runtime libraries (modules)
++behind a consistent, portable interface.
+ 
+ EOF
+ 
+@@ -497,6 +504,11 @@
+   $release_type eq 'stable'
+     or print_changelog_deltas ($package_name, $prev_version);
+ 
++  print <<EOF;
++
++Enjoy!
++EOF
++
+   exit 0;
+ }
+ 
diff --git a/gl/build-aux/do-release-commit-and-tag.diff b/gl/build-aux/do-release-commit-and-tag.diff
new file mode 100644
index 0000000..9dfa795
--- /dev/null
+++ b/gl/build-aux/do-release-commit-and-tag.diff
@@ -0,0 +1,22 @@
+--- gnulib/build-aux/do-release-commit-and-tag	2011-10-19 22:37:21.000000000 +0700
++++ gl/build-aux/do-release-commit-and-tag	2011-10-21 15:09:12.000000000 +0700
+@@ -74,6 +74,10 @@
+   esac
+ }
+ 
++for gsort in $SORT gsort sort; do
++  echo 1|$gsort -V >/dev/null 2>/dev/null && break
++done
++
+ branch=master
+ case $1 in
+   --branch) shift; branch=$1; shift ;;
+@@ -95,7 +99,7 @@
+   || die 'failed to determine previous version number from .prev-version'
+ 
+ # Verify that $ver is sensible (> .prev-version).
+-case $(printf "$prev_ver\n$ver\n"|sort -V -u|tr '\n' ':') in
++case $(printf "$prev_ver\n$ver\n"|$gsort -V -u|tr '\n' ':') in
+   "$prev_ver:$ver:") ;;
+   *) die "invalid version: $ver";;
+ esac
diff --git a/gl/top/README-release.diff b/gl/top/README-release.diff
new file mode 100644
index 0000000..f98afa3
--- /dev/null
+++ b/gl/top/README-release.diff
@@ -0,0 +1,40 @@
+--- gnulib/top/README-release	2011-10-23 14:32:58.000000000 +0700
++++ gl/top/README-release	2011-10-23 14:38:40.000000000 +0700
+@@ -1,5 +1,11 @@
+ Here are most of the steps we (maintainers) follow when making a release.
+ 
++* If you don't yet have gnu ftp upload rights, read this:
++
++    https://www.gnu.org/prep/maintain/html_node/Automated-Upload-Registration.html#Automated-Upload-Registration
++
++* Make sure your locale is sane, e.g. by exporting LC_ALL=C.
++
+ * start from a clean, up-to-date git directory.
+ 
+     make -k maintainer-clean || { ./configure && make maintainer-clean; }
+@@ -18,12 +24,24 @@
+ 
+     http://hydra.nixos.org/jobset/gnu/@PACKAGE@-master
+ 
+-* Run "./bootstrap && ./configure".  This downloads any new translations:
++* Double check that serial number updates in public m4 files weren't
++  forgotten since last release (they should be updated in git along with
++  commits that require it so that users can work with git snapshots).
++
++* Update the LTDL_VERSION_INFO in libltdl/Makefile.inc for changes since
++  the last release.
++
++* Run "./bootstrap && ./configure".
+ 
+ * Pre-release testing:
+   Ensure that "make check syntax-check" succeeds.
+ 
+ * Run "make distcheck"
++  and `make distcheck DISTCHECK_CONFIGURE_FLAGS=--disable-ltdl-install'
++  and `make distcheck DISTCHECK_CONFIGURE_FLAGS=--program-prefix=g'
++  and `make distcheck DISTCHECK_CONFIGURE_FLAGS=--disable-shared'
++  and `make distcheck CC=g++'
++  If there are any problems, fix them and start again.
+ 
+ * Set the date, version number, and release type [stable/alpha/beta] on
+   line 3 of NEWS, commit that, and tag the release by running e.g.,
diff --git a/libltdl/config/.gitignore b/libltdl/config/.gitignore
index d6138cc..3bbb989 100644
--- a/libltdl/config/.gitignore
+++ b/libltdl/config/.gitignore
@@ -1,6 +1,10 @@
+/announce-gen
 /compile
 /depcomp
+/do-release-commit-and-tag
 /gendocs.sh
+/gnu-web-doc-update
+/gnupload
 /install-sh
 /ltmain.in
 /ltmain.sh
diff --git a/libltdl/config/cvsu b/libltdl/config/cvsu
new file mode 100755
index 0000000..741f6b2
--- /dev/null
+++ b/libltdl/config/cvsu
@@ -0,0 +1,512 @@
+#! /usr/bin/perl -w
+
+# cvsu - do a quick check to see what files are out of date.
+#
+# Copyright (C) 2000-2005  Pavel Roskin <[email-masked]>
+# Initially written by Tom Tromey <[email-masked]>
+# Completely rewritten by Pavel Roskin <[email-masked]>
+#
+# 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/>.
+
+
+require 5.004;
+use Getopt::Long;
+use File::Basename;
+use Time::Local;
+use strict;
+
+use vars qw($list_types %messages %options @batch_list $batch_cmd
+            $no_recurse $explain_type $find_mode $short_print
+            $no_cvsignore $nolinks $file $single_filename $curr_dir
+            @common_ignores $ignore_rx %entries %subdirs %removed);
+
+use constant SUBDIR_FOUND => 1;
+use constant SUBDIR_CVS   => 2;
+
+# This list comes from the CVS manual.
+use constant STANDARD_IGNORES =>
+        ('RCS', 'SCCS', 'CVS', 'CVS.adm', 'RCSLOG', 'cvslog.*', 'tags',
+         'TAGS', '.make.state', '.nse_depinfo', '*~', '#*', '.#*', ',*',
+         "_\$*", "*\$", '*.old', '*.bak', '*.BAK', '*.orig', '*.rej',
+         '.del-*', '*.a', '*.olb', '*.o', '*.obj', '*.so', '*.exe',
+         '*.Z', '*.elc', '*.ln', 'core');
+
+# 3-letter month names in POSIX locale, for fast date decoding
+my %months = (
+    "Jan" => 0,
+    "Feb" => 1,
+    "Mar" => 2,
+    "Apr" => 3,
+    "May" => 4,
+    "Jun" => 5,
+    "Jul" => 6,
+    "Aug" => 7,
+    "Sep" => 8,
+    "Oct" => 9,
+    "Nov" => 10,
+    "Dec" => 11
+);
+
+# print usage information and exit
+sub usage ()
+{
+    print "Usage:\n" .
+        "  cvsu [OPTIONS] [FILE] ...\n" .
+        "Options:\n" .
+        "  --local		Disable recursion\n" .
+        "  --explain		Verbosely print status of files\n" .
+        "  --find		Emulate find - filenames only\n" .
+        "  --short		Don't print paths\n" .
+        "  --ignore		Don't read .cvsignore\n" .
+        "  --messages		List known file types and long messages\n" .
+        "  --nolinks		Disable recognizing hard and soft links\n" .
+        "  --types=[^]LIST	Print only file types [not] from LIST\n" .
+        "  --batch=COMMAND	Execute this command on files\n" .
+        "  --help		Print this usage information\n" .
+        "  --version		Print version number\n" .
+        "Abbreviations and short options are supported\n";
+    exit 0;
+}
+
+# print version information and exit
+sub version ()
+{
+    print "cvsu - CVS offline examiner, version 0.2.3\n";
+    exit 0;
+}
+
+# If types begin with '^', make inversion
+sub adjust_types ()
+{
+    if ($list_types =~ m{^\^(.*)$}) {
+        $list_types = "";
+        foreach (keys %messages) {
+            $list_types .= $_
+                if (index ($1, $_) < 0);
+        }
+    }
+}
+
+# list known messages and exit
+sub list_messages ()
+{
+    my $default_mark;
+    print "Recognizable file types are:\n";
+    foreach (sort keys %messages) {
+        if (index($list_types, $_) >= 0) {
+            $default_mark = "*";
+        } else {
+            $default_mark = " ";
+        }
+        print "  $default_mark $_ $messages{$_}\n";
+    }
+    print "* indicates file types listed by default\n";
+    exit 0;
+}
+
+# Initialize @common_ignores
+# Also read $HOME/.cvsignore and append it to @common_ignores
+sub init_ignores ()
+{
+    my $HOME = $ENV{"HOME"};
+
+    push @common_ignores, STANDARD_IGNORES;
+
+    unless (defined($HOME)) {
+        return;
+    }
+
+    my $home_cvsignore = "${HOME}/.cvsignore";
+
+    if (-f "$home_cvsignore") {
+
+        unless (open (CVSIGNORE, "< $home_cvsignore")) {
+            error ("couldn't open $home_cvsignore: $!");
+        }
+
+        while (<CVSIGNORE>) {
+            push (@common_ignores, split);
+        }
+
+        close (CVSIGNORE);
+    }
+
+    my $CVSIGNOREENV = $ENV{"CVSIGNORE"};
+
+    unless (defined($CVSIGNOREENV)) {
+        return;
+    }
+
+    my @ignores_var = split (/ /, $CVSIGNOREENV);
+    push (@common_ignores, @ignores_var);
+
+}
+
+# Print message and exit (like "die", but without raising an exception).
+# Newline is added at the end.
+sub error ($)
+{
+        print STDERR "cvsu: ERROR: " . shift(@_) . "\n";
+        exit 1;
+}
+
+# execute commands from @exec_list with $exec_cmd
+sub do_batch ()
+{
+        my @cmd_list = split (' ', $batch_cmd);
+        system (@cmd_list,  @batch_list);
+}
+
+# print files status
+# Parameter 1: status in one-letter representation
+sub file_status ($)
+{
+    my $type = shift (@_);
+    my $item;
+    my $pathfile;
+
+    return
+        if $ignore_rx ne '' && $type =~ /[?SLD]/ && $file =~ /$ignore_rx/;
+
+    return
+        if (index($list_types, $type) < 0);
+
+    $pathfile = $curr_dir . $file;
+
+    if (defined($batch_cmd)) {
+        push (@batch_list, $pathfile);
+        # 1000 items in the command line might be too much for HP-UX
+        if ($#batch_list > 1000) {
+            do_batch();
+            undef @batch_list;
+        }
+    }
+
+    if ($short_print) {
+        $item = $file;
+    } else {
+        $item = $pathfile;
+    }
+
+    if ($find_mode) {
+        print "$item\n";
+    } else {
+        $type = $messages{$type}
+            if ($explain_type);
+        print "$type $item\n";
+    }
+}
+
+# load entries from CVS/Entries and CVS/Entries.Log
+# Parameter 1: file name for CVS/Entries
+# Return: list of entries in the format used in CVS/Entries
+sub load_entries ($);
+sub load_entries ($)
+{
+    my $entries_file = shift (@_);
+    my $entries_log_file = "$entries_file.Log";
+    my %ent = ();
+
+    unless (open (ENTRIES, "< $entries_file")) {
+        error ("couldn't open $entries_file: $!");
+    }
+    while (<ENTRIES>) {
+        chomp;
+        $ent{$_} = 1;
+    }
+    close (ENTRIES);
+
+    if (open (ENTRIES, "< $entries_log_file")) {
+        while (<ENTRIES>) {
+            chomp;
+            if ( m{^A (.+)} ) {
+                $ent{$1} = 1;
+            } elsif ( m{^R (.+)} ) {
+                delete $ent{$1};
+            } else {
+                # Note: "cvs commit" helps even when you are offline
+                error ("$entries_log_file:$.: unrecognizable line, " .
+                        "try \"cvs commit\"");
+            }
+        }
+        close (ENTRIES);
+    }
+
+    return keys %ent;
+}
+
+# process one directory
+# Parameter 1: directory name
+sub process_arg ($);
+sub process_arg ($)
+{
+    my $arg = shift (@_);
+    my %found_files = ();
+
+    # $file, $curr_dir, and $ignore_rx must be seen in file_status
+    local $file = "";
+    local $ignore_rx = "";
+    local $single_filename = 0;
+
+    if ( $arg eq "" or -d $arg ) {
+        $curr_dir = $arg;
+        my $real_curr_dir = $curr_dir eq "" ? "." : $curr_dir;
+
+        error ("$real_curr_dir is not a directory")
+            unless ( -d $real_curr_dir );
+
+        # Scan present files.
+        file_status (".");
+        opendir (DIR, $real_curr_dir) ||
+            error ("couldn't open directory $real_curr_dir: $!");
+        foreach (readdir (DIR)) {
+            $found_files {$_} = 1;
+        }
+        closedir (DIR);
+    } else {
+        $single_filename = basename $arg;
+        $curr_dir = dirname $arg;
+        $found_files{$single_filename} = 1 if lstat $arg;
+    }
+
+    $curr_dir .= "/"
+        unless ( $curr_dir eq "" || $curr_dir =~ m{/$} );
+
+    # Scan CVS/Entries.
+    my %entries = ();
+    my %subdirs = ();
+    my %removed = ();
+
+    foreach ( load_entries ("${curr_dir}CVS/Entries") ) {
+        if ( m{^D/([^/]+)/} ) {
+            $subdirs{$1} = SUBDIR_FOUND if !$single_filename;
+        } elsif ( m{^/([^/]+)/([^/])[^/]*/([^/]*)/} ) {
+            if ( !$single_filename or $single_filename eq $1 ) {
+                $entries{$1} = $3;
+                $removed{$1} = 1
+                    if $2 eq '-';
+            }
+        } elsif ( m{^D$} ) {
+            next;
+        } else {
+            error ("${curr_dir}CVS/Entries: unrecognizable line");
+        }
+    }
+
+    if ( $single_filename && !$entries{$single_filename} &&
+         !$found_files{$single_filename} ) {
+        error ("nothing known about $arg");
+    }
+
+    # Scan .cvsignore if any
+    unless ($no_cvsignore) {
+        my (@ignore_list) = ();
+
+        if (-f "${curr_dir}.cvsignore") {
+            open (CVSIGNORE, "< ${curr_dir}.cvsignore")
+                || error ("couldn't open ${curr_dir}.cvsignore: $!");
+            while (<CVSIGNORE>) {
+                push (@ignore_list, split);
+            }
+            close (CVSIGNORE);
+        }
+
+        my ($iter);
+        foreach $iter (@ignore_list, @common_ignores) {
+            if ($iter eq '!') {
+                $ignore_rx = ''
+            } else {
+                if ($ignore_rx eq '') {
+                    $ignore_rx = '^(';
+                } else {
+                    $ignore_rx .= '|';
+                }
+                $ignore_rx .= glob_to_rx ($iter);
+            }
+        }
+        $ignore_rx .= ')$'
+            if $ignore_rx ne '';
+    }
+
+    # File is missing
+    foreach $file (sort keys %entries) {
+        unless ($found_files{$file}) {
+            if ($removed{$file}) {
+                file_status("R");
+            } else {
+                file_status("U");
+            }
+        }
+    }
+
+    foreach $file (sort keys %found_files) {
+        next if ($file eq '.' || $file eq '..');
+        lstat ($curr_dir . $file) ||
+            error ("lstat() failed on $curr_dir . $file");
+        if (! $nolinks && -l _) {
+            file_status ("L");
+        } elsif (-d _) {
+            if ($file eq 'CVS') {
+                file_status ("C");
+            } elsif ($subdirs{$file}) {
+                $subdirs{$file} = SUBDIR_CVS;
+            } else {
+                file_status ("D"); # Unknown directory
+            }
+        } elsif (! (-f _) && ! (-l _)) {
+            file_status ("S"); # This must be something very special
+        } elsif (! $nolinks && (stat _) [3] > 1 ) {
+            file_status ("H"); # Hard link
+        } elsif (! $entries{$file}) {
+            file_status ("?");
+        } elsif ($entries{$file} =~ /^Initial |^dummy /) {
+            file_status ("A");
+        } elsif ($entries{$file} =~ /^Result of merge/) {
+            file_status ("G");
+        } elsif ($entries{$file} !~
+                /^(...) (...) (..) (..):(..):(..) (....)$/) {
+            error ("Invalid timestamp for $curr_dir$file: $entries{$file}");
+        } else {
+            my $cvtime = timegm($6, $5, $4, $3, $months{$2}, $7 - 1900);
+            my $mtime = (stat _) [9];
+            if ($cvtime == $mtime) {
+                file_status ("F");
+            } elsif ($cvtime < $mtime) {
+                file_status ("M");
+            } else {
+                file_status ("O");
+            }
+        }
+    }
+
+    # Now do directories.
+    unless ($no_recurse) {
+        my $save_curr_dir = $curr_dir;
+        foreach $file (sort keys %subdirs) {
+            if ($subdirs{$file} == SUBDIR_FOUND) {
+                $curr_dir = $save_curr_dir;
+                file_status ("X");
+            } elsif ($subdirs{$file} == SUBDIR_CVS) {
+                process_arg ($save_curr_dir . $file)
+            }
+        }
+    }
+}
+
+# Turn a glob into a regexp without recognizing square brackets.
+sub glob_to_rx_simple ($)
+{
+    my ($expr) = @_;
+    # Quote all non-word characters, convert ? to . and * to .*
+    $expr =~ s/(\W)/\\$1/g;
+    $expr =~ s/\\\*/.*/g;
+    $expr =~ s/\\\?/./g;
+    return $expr;
+}
+
+# Turn a glob into a regexp
+sub glob_to_rx ($)
+{
+    my $result = '';
+    my ($expr) = @_;
+    # Find parts in square brackets and copy them literally
+    # Text outside brackets is processed by glob_to_rx_simple()
+    while ($expr ne '') {
+        if ($expr =~ /^(.*?)(\[.*?\])(.*)/) {
+            $expr = $3;
+            $result .= glob_to_rx_simple ($1) . $2;
+        } else {
+            $result .= glob_to_rx_simple ($expr);
+            last;
+        }
+    }
+    return $result;
+}
+
+sub Main ()
+{
+    # types of files to be listed
+    $list_types = "^.FCL";
+
+    # long status messages
+    %messages = (
+        "?" => "Unlisted file",
+        "." => "Known directory",
+        "F" => "Up-to-date file",
+        "C" => "CVS admin directory",
+        "M" => "Modified file",
+        "S" => "Special file",
+        "D" => "Unlisted directory",
+        "L" => "Symbolic link",
+        "H" => "Hard link",
+        "U" => "Lost file",
+        "X" => "Lost directory",
+        "A" => "Newly added",
+        "O" => "Older copy",
+        "G" => "Result of merge",
+        "R" => "Removed file"
+    );
+
+    undef @batch_list;		# List of files for batch processing
+    undef $batch_cmd;		# Command to be executed on files
+    $no_recurse = 0;		# If this is set, do only local files
+    $explain_type = 0;		# Verbosely print status of files
+    $find_mode = 0;		# Don't print status at all
+    $short_print = 0;		# Print only filenames without path
+    $no_cvsignore = 0;		# Ignore .cvsignore
+    $nolinks = 0;		# Do not test for soft- or hard-links
+    my $want_msg = 0;		# List possible filetypes and exit
+    my $want_help = 0;		# Print help and exit
+    my $want_ver = 0;		# Print version and exit
+
+    my %options = (
+        "types=s"  => \$list_types,
+        "batch=s"  => \$batch_cmd,
+        "local"	   => \$no_recurse,
+        "explain"  => \$explain_type,
+        "find"	   => \$find_mode,
+        "short"	   => \$short_print,
+        "ignore"   => \$no_cvsignore,
+        "messages" => \$want_msg,
+        "nolinks"  => \$nolinks,
+        "help"     => \$want_help,
+        "version"  => \$want_ver
+    );
+
+    GetOptions(%options);
+
+    adjust_types();
+
+    list_messages() if $want_msg;
+    usage() if $want_help;
+    version() if $want_ver;
+
+    unless ($no_cvsignore) {
+        init_ignores();
+    }
+
+    if ($#ARGV < 0) {
+        @ARGV = ("");
+    }
+
+    foreach (@ARGV) {
+        process_arg ($_);
+    }
+
+    if ($#batch_list >= 0) {
+            do_batch();
+    }
+}
+
+Main();
-- 
1.7.7

Cheers,
-- 
Gary V. Vaughan (gary AT gnu DOT org)