changeset 10347:f818c7d254f6

Merge branch 'master' of ssh://bonzini@git.sv.gnu.org/srv/git/gnulib
author Paolo Bonzini <bonzini@gnu.org>
date Wed, 20 Aug 2008 10:00:53 +0200
parents 640791e12ea5 (current diff) 1d6d83874993 (diff)
children a4ab54929093
files lib/strverscmp.h
diffstat 21 files changed, 259 insertions(+), 89 deletions(-) [+]
line wrap: on
line diff
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,74 @@
+2008-08-19  Eric Blake  <ebb9@byu.net>
+
+	test-c-stack: fix compilation failure on FreeBSD 5.0
+	* tests/test-c-stack.c [HAVE_SETRLIMIT]: Include prerequisite
+	headers before <sys/resource.h>.
+	* doc/posix-headers/sys_resource.texi (sys/resource.h): Document
+	the bug.
+	Reported by Nelson H. F. Beebe.
+
+	strverscmp: migrate from "strverscmp.h" to <string.h>
+	* modules/string (Makefile.am): Add new hooks.
+	* modules/strverscmp (Files): Remove strverscmp.h.
+	(Depends-on): Add string.
+	(configure.ac): Add indicator.
+	(Include): Mention new header.
+	* m4/string_h.m4 (gl_HEADER_STRING_H_DEFAULTS): Provide new
+	defaults.
+	* m4/strverscmp.m4 (gl_FUNC_STRVERSCMP): Inform string module of
+	results.
+	* lib/strverscmp.h: Delete.
+	* lib/string.in.h (strverscmp): Provide declaration, when needed.
+	* tests/test-strverscmp.c (includes): Adjust client.
+	* lib/check-version.c (includes): Likewise.
+	* NEWS: Document the change.
+
+	strverscmp: add unit test
+	* modules/strverscmp-tests: New file.
+	* tests/test-strverscmp.c: Likewise.
+
+2008-08-19  Simon Josefsson  <simon@josefsson.org>
+
+	* lib/gc-gnulib.c: Indentation cleanup.  Add some comments
+	regarding Windows crypto stuff, from Mono.
+
+2008-08-19  Adam Strzelecki <ono@java.pl>  (tiny change)
+
+	* lib/gc-gnulib.c: Use CRYPT_VERIFY_CONTEXT.  Try to use Intel CSP
+	if present, for intel RND.  Return error on failures.
+
+2008-08-18  Ben Pfaff  <blp@gnu.org>
+
+	gitlog-to-changelog: give better diagnostic for failed pipe-open
+	* build-aux/gitlog-to-changelog: Improve error message: suggest
+	that the version of Git may be too old.
+
+2008-08-18  Simon Josefsson  <simon@josefsson.org>
+
+	* m4/autobuild.m4: Use TZ=UTC to avoid time zone complexity.  Use
+	ISO 8601 format.  Suggested by Greg Troxel <gdt@ir.bbn.com>.
+
+2008-08-18  Bruno Haible  <bruno@clisp.org>
+
+	* lib/glthread/thread.h [USE_SOLARIS_THREADS]: Use thread_in_use(), not
+	pthread_in_use().
+
+2008-08-18  Bruno Haible  <bruno@clisp.org>
+
+	* lib/glthread/threadlib.c: Include <pthread.h>.
+
+2008-08-18  Bruno Haible  <bruno@clisp.org>
+
+	* lib/glthread/lock.h [USE_SOLARIS_THREADS]: Fix
+	glthread_recursive_lock_* macros.
+	* lib/glthread/lock.c (glthread_recursive_lock_destroy_multithreaded):
+	Fix syntax error.
+
+2008-08-18  Bruno Haible  <bruno@clisp.org>
+
+	* lib/glthread/thread.c: Avoid forcing a context switch right after
+	thread creation.
+
 2008-08-17  Bruno Haible  <bruno@clisp.org>
 
 	* lib/glthread/thread.c: New file, based on code from tests/test-lock.c.
--- a/NEWS
+++ b/NEWS
@@ -6,6 +6,9 @@
 
 Date        Modules         Changes
 
+2008-08-19  strverscmp      The include file is changed from "strverscmp.h"
+                            to <string.h>.
+
 2008-08-14  lock            The include file is changed from "lock.h"
                             to "glthread/lock.h".
             tls             The include file is changed from "tls.h"
--- a/build-aux/gitlog-to-changelog
+++ b/build-aux/gitlog-to-changelog
@@ -1,7 +1,7 @@
 #!/usr/bin/perl
 # Convert git log output to ChangeLog format.
 
-my $VERSION = '2008-02-10 10:03'; # UTC
+my $VERSION = '2008-08-19 05:01'; # UTC
 # The definition above must lie within the first 8 lines in order
 # for the Emacs time-stamp write hook (at end) to update it.
 # If you change this file with Emacs, please let the write hook
@@ -106,7 +106,8 @@
   my @cmd = (qw (git log --log-size), "--since=$since_date",
              '--pretty=format:%ct  %an  <%ae>%n%n%s%n%b%n');
   open PIPE, '-|', @cmd
-    or die "$ME: failed to run `". quoted_cmd (@cmd) ."': $!\n";
+    or die ("$ME: failed to run `". quoted_cmd (@cmd) ."': $!\n"
+            . "(Is your Git too old?  Version 1.5.1 or later is required.)\n");
 
   my $prev_date_line = '';
   while (1)
--- a/doc/posix-headers/sys_resource.texi
+++ b/doc/posix-headers/sys_resource.texi
@@ -12,6 +12,11 @@
 Portability problems not fixed by Gnulib:
 @itemize
 @item
+On some platforms, this header file requires that <sys/types.h> and
+<sys/time.h> already be included:
+FreeBSD 5.0.
+
+@item
 This header file is missing on some platforms:
 mingw.
 @end itemize
--- a/lib/check-version.c
+++ b/lib/check-version.c
@@ -1,6 +1,6 @@
 /* check-version.h --- Check version string compatibility.
-   Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006 Free
-   Software Foundation, Inc.
+   Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006,
+   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
@@ -23,7 +23,7 @@
 #include <config.h>
 
 #include <stddef.h>
-#include <strverscmp.h>
+#include <string.h>
 
 /* Get specification. */
 #include "check-version.h"
--- a/lib/gc-gnulib.c
+++ b/lib/gc-gnulib.c
@@ -78,6 +78,12 @@
 #  include <windows.h>
 #  include <wincrypt.h>
 HCRYPTPROV g_hProv = 0;
+#  ifndef PROV_INTEL_SEC
+#   define PROV_INTEL_SEC 22
+#  endif
+#  ifndef CRYPT_VERIFY_CONTEXT
+#   define CRYPT_VERIFY_CONTEXT 0xF0000000
+#  endif
 # endif
 #endif
 
@@ -86,9 +92,22 @@
 {
 #ifdef GNULIB_GC_RANDOM
 # if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
-  if(g_hProv)
-    CryptReleaseContext(g_hProv, 0);
-  CryptAcquireContext(&g_hProv, NULL, NULL, PROV_RSA_FULL, 0);
+  if (g_hProv)
+    CryptReleaseContext (g_hProv, 0);
+
+  /* There is no need to create a container for just random data, so
+     we can use CRYPT_VERIFY_CONTEXT (one call) see:
+     http://blogs.msdn.com/dangriff/archive/2003/11/19/51709.aspx */
+
+  /* We first try to use the Intel PIII RNG if drivers are present */
+  if (!CryptAcquireContext (&g_hProv, NULL, NULL,
+			    PROV_INTEL_SEC, CRYPT_VERIFY_CONTEXT))
+    {
+      /* not a PIII or no drivers available, use default RSA CSP */
+      if (!CryptAcquireContext (&g_hProv, NULL, NULL,
+				PROV_RSA_FULL, CRYPT_VERIFY_CONTEXT))
+	return GC_RANDOM_ERROR;
+    }
 # endif
 #endif
 
@@ -100,9 +119,9 @@
 {
 #ifdef GNULIB_GC_RANDOM
 # if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
-  if(g_hProv)
+  if (g_hProv)
     {
-      CryptReleaseContext(g_hProv, 0);
+      CryptReleaseContext (g_hProv, 0);
       g_hProv = 0;
     }
 # endif
@@ -119,9 +138,9 @@
 randomize (int level, char *data, size_t datalen)
 {
 #if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
-  if(!g_hProv)
+  if (!g_hProv)
     return GC_RANDOM_ERROR;
-  CryptGenRandom(g_hProv, (DWORD)datalen, data);
+  CryptGenRandom (g_hProv, (DWORD) datalen, data);
 #else
   int fd;
   const char *device;
@@ -206,9 +225,11 @@
 {
   return;
 }
+
 /* Ciphers. */
 
-typedef struct _gc_cipher_ctx {
+typedef struct _gc_cipher_ctx
+{
   Gc_cipher alg;
   Gc_cipher_mode mode;
 #ifdef GNULIB_GC_ARCTWO
@@ -351,7 +372,7 @@
 	char keyMaterial[RIJNDAEL_MAX_KEY_SIZE + 1];
 
 	for (i = 0; i < keylen; i++)
-	  sprintf (&keyMaterial[2*i], "%02x", key[i] & 0xFF);
+	  sprintf (&keyMaterial[2 * i], "%02x", key[i] & 0xFF);
 
 	rc = rijndaelMakeKey (&ctx->aesEncKey, RIJNDAEL_DIR_ENCRYPT,
 			      keylen * 8, keyMaterial);
@@ -409,7 +430,7 @@
 	    char ivMaterial[2 * RIJNDAEL_MAX_IV_SIZE + 1];
 
 	    for (i = 0; i < ivlen; i++)
-	      sprintf (&ivMaterial[2*i], "%02x", iv[i] & 0xFF);
+	      sprintf (&ivMaterial[2 * i], "%02x", iv[i] & 0xFF);
 
 	    rc = rijndaelCipherInit (&ctx->aesContext, RIJNDAEL_MODE_CBC,
 				     ivMaterial);
@@ -448,7 +469,7 @@
 
 	case GC_CBC:
 	  for (; len >= ARCTWO_BLOCK_SIZE; len -= ARCTWO_BLOCK_SIZE,
-		 data += ARCTWO_BLOCK_SIZE)
+	       data += ARCTWO_BLOCK_SIZE)
 	    {
 	      size_t i;
 	      for (i = 0; i < ARCTWO_BLOCK_SIZE; i++)
@@ -457,7 +478,7 @@
 			      ARCTWO_BLOCK_SIZE);
 	      memcpy (ctx->arctwoIV, data, ARCTWO_BLOCK_SIZE);
 	    }
-	    break;
+	  break;
 
 	default:
 	  return GC_INVALID_CIPHER;
@@ -518,7 +539,7 @@
 
 	case GC_CBC:
 	  for (; len >= ARCTWO_BLOCK_SIZE; len -= ARCTWO_BLOCK_SIZE,
-		 data += ARCTWO_BLOCK_SIZE)
+	       data += ARCTWO_BLOCK_SIZE)
 	    {
 	      char tmpIV[ARCTWO_BLOCK_SIZE];
 	      size_t i;
@@ -587,7 +608,8 @@
 
 #define MAX_DIGEST_SIZE 20
 
-typedef struct _gc_hash_ctx {
+typedef struct _gc_hash_ctx
+{
   Gc_hash alg;
   Gc_hash_mode mode;
   char hash[MAX_DIGEST_SIZE];
--- a/lib/glthread/lock.c
+++ b/lib/glthread/lock.c
@@ -445,7 +445,7 @@
 {
   if (lock->owner != (pthread_t) 0)
     return EBUSY;
-  return (pthread_mutex_destroy (&lock->mutex);
+  return pthread_mutex_destroy (&lock->mutex);
 }
 
 # endif
--- a/lib/glthread/lock.h
+++ b/lib/glthread/lock.h
@@ -577,33 +577,13 @@
 # define gl_recursive_lock_initializer \
     { DEFAULTMUTEX, (thread_t) 0, 0 }
 # define glthread_recursive_lock_init(LOCK) \
-    do                                          \
-      {                                         \
-        if (thread_in_use ())                   \
-          glthread_recursive_lock_init_multithreaded (LOCK); \
-      }                                         \
-    while (0)
+    (thread_in_use () ? glthread_recursive_lock_init_multithreaded (LOCK) : 0)
 # define glthread_recursive_lock_lock(LOCK) \
-    do                                          \
-      {                                         \
-        if (thread_in_use ())                   \
-          glthread_recursive_lock_lock_multithreaded (LOCK); \
-      }                                         \
-    while (0)
+    (thread_in_use () ? glthread_recursive_lock_lock_multithreaded (LOCK) : 0)
 # define glthread_recursive_lock_unlock(LOCK) \
-    do                                            \
-      {                                           \
-        if (thread_in_use ())                     \
-          glthread_recursive_lock_unlock_multithreaded (LOCK); \
-      }                                           \
-    while (0)
+    (thread_in_use () ? glthread_recursive_lock_unlock_multithreaded (LOCK) : 0)
 # define glthread_recursive_lock_destroy(LOCK) \
-    do                                             \
-      {                                            \
-        if (thread_in_use ())                      \
-          glthread_recursive_lock_destroy_multithreaded (LOCK); \
-      }                                            \
-    while (0)
+    (thread_in_use () ? glthread_recursive_lock_destroy_multithreaded (LOCK) : 0)
 extern int glthread_recursive_lock_init_multithreaded (gl_recursive_lock_t *lock);
 extern int glthread_recursive_lock_lock_multithreaded (gl_recursive_lock_t *lock);
 extern int glthread_recursive_lock_unlock_multithreaded (gl_recursive_lock_t *lock);
--- a/lib/glthread/thread.c
+++ b/lib/glthread/thread.c
@@ -39,6 +39,7 @@
     /* Fields for managing the association between thread id and handle.  */
     DWORD volatile id;
     HANDLE volatile handle;
+    CRITICAL_SECTION handle_lock;
     struct thread_extra * volatile next;
     /* Fields for managing the exit value.  */
     void * volatile result;
@@ -60,7 +61,20 @@
 {
   struct thread_extra *xarg = (struct thread_extra *)varg;
 
+  EnterCriticalSection (&xarg->handle_lock);
   xarg->id = GetCurrentThreadId ();
+  /* Create a new handle for the thread only if the parent thread did not yet
+     fill in the handle.  */
+  if (xarg->handle == NULL)
+    {
+      HANDLE this_thread;
+      if (!DuplicateHandle (GetCurrentProcess (), GetCurrentThread (),
+			    GetCurrentProcess (), &this_thread,
+			    0, FALSE, DUPLICATE_SAME_ACCESS))
+	abort ();
+      xarg->handle = this_thread;
+    }
+  LeaveCriticalSection (&xarg->handle_lock);
   /* Add xarg to the list of running thread_extra.  */
   gl_lock_lock (running_lock);
   if (!(xarg->id == GetCurrentThreadId ()))
@@ -82,6 +96,8 @@
     (struct thread_extra *) malloc (sizeof (struct thread_extra));
   if (x == NULL)
     return ENOMEM;
+  x->handle = NULL;
+  InitializeCriticalSection (&x->handle_lock);
   x->result = NULL; /* just to be deterministic */
   x->func = func;
   x->arg = arg;
@@ -89,16 +105,21 @@
     DWORD thread_id;
     HANDLE thread_handle;
 
-    gl_lock_lock (running_lock);
     thread_handle = CreateThread (NULL, 100000, wrapper_func, x, 0, &thread_id);
     if (thread_handle == NULL)
       {
-	gl_lock_unlock (running_lock);
+	DeleteCriticalSection (&x->handle_lock);
+	free (x);
 	return EAGAIN;
       }
+    EnterCriticalSection (&x->handle_lock);
     x->id = thread_id;
-    x->handle = thread_handle;
-    gl_lock_unlock (running_lock);
+    if (x->handle == NULL)
+      x->handle = thread_handle;
+    else
+      /* x->handle was already set by the thread itself.  */
+      CloseHandle (thread_handle);
+    LeaveCriticalSection (&x->handle_lock);
     *threadp = thread_id;
     return 0;
   }
@@ -114,10 +135,8 @@
 
   /* Find the thread handle that corresponds to the thread id.
      The thread argument must come from either the parent thread or from the
-     thread itself.  So at this point, either glthread_create_func was
-     completed (and x->handle set), or x->func was invoked (and that can
-     only be after the running_lock was acquired, hence after
-     glthread_create_func released it, hence x->handle is set as well).  */
+     thread itself.  So at this point, either glthread_create_func or
+     wrapper_func (whichever was executed first) has filled in x->handle.  */
   thread_handle = NULL;
   gl_lock_lock (running_lock);
   {
@@ -139,7 +158,7 @@
   /* Remove the 'struct thread_extra' from running_threads.  */
   gl_lock_lock (running_lock);
   {
-    struct thread_extra **xp;
+    struct thread_extra * volatile *xp;
     for (xp = &running_threads; *xp != NULL; xp = &(*xp)->next)
       if ((*xp)->id == thread)
 	{
@@ -149,6 +168,7 @@
 	  if (x->handle != thread_handle)
 	    abort ();
 	  *xp = x->next;
+	  DeleteCriticalSection (&x->handle_lock);
 	  free (x);
 	  break;
 	}
--- a/lib/glthread/thread.h
+++ b/lib/glthread/thread.h
@@ -250,13 +250,13 @@
 # define glthread_create(THREADP, FUNC, ARG) \
     (thread_in_use () ? thr_create (NULL, 0, FUNC, ARG, 0, THREADP) : 0)
 # define glthread_sigmask(HOW, SET, OSET) \
-    (pthread_in_use () ? sigprocmask (HOW, SET, OSET) : 0)
+    (thread_in_use () ? sigprocmask (HOW, SET, OSET) : 0)
 # define glthread_join(THREAD, RETVALP) \
-    (pthread_in_use () ? thr_join (THREAD, NULL, RETVALP) : 0)
+    (thread_in_use () ? thr_join (THREAD, NULL, RETVALP) : 0)
 # define gl_thread_self() \
-    (pthread_in_use () ? (void *) thr_self () : 0)
+    (thread_in_use () ? (void *) thr_self () : 0)
 # define gl_thread_exit(RETVAL) \
-    (pthread_in_use () ? thr_exit (RETVAL) : 0)
+    (thread_in_use () ? thr_exit (RETVAL) : 0)
 # define glthread_atfork(PREPARE_FUNC, PARENT_FUNC, CHILD_FUNC) 0
 
 # ifdef __cplusplus
--- a/lib/glthread/threadlib.c
+++ b/lib/glthread/threadlib.c
@@ -25,6 +25,8 @@
 
 /* Use the POSIX threads library.  */
 
+# include <pthread.h>
+
 # if PTHREAD_IN_USE_DETECTION_HARD
 
 /* The function to be executed by a dummy thread.  */
--- a/lib/string.in.h
+++ b/lib/string.in.h
@@ -576,6 +576,18 @@
      strsignal (a))
 #endif
 
+#if @GNULIB_STRVERSCMP@
+# if !@HAVE_STRVERSCMP@
+extern int strverscmp (const char *, const char *);
+# endif
+#elif defined GNULIB_POSIXCHECK
+# undef strverscmp
+# define strverscmp(a, b) \
+    (GL_LINK_WARNING ("strverscmp is unportable - " \
+                      "use gnulib module strverscmp for portability"), \
+     strverscmp (a, b))
+#endif
+
 
 #ifdef __cplusplus
 }
deleted file mode 100644
--- a/lib/strverscmp.h
+++ /dev/null
@@ -1,24 +0,0 @@
-/* Compare strings while treating digits characters numerically.
-
-   Copyright (C) 1997, 2003 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 2, 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.  */
-
-#ifndef STRVERSCMP_H_
-# define STRVERSCMP_H_
-
-int strverscmp (const char *, const char *);
-
-#endif /* not STRVERSCMP_H_ */
--- a/m4/autobuild.m4
+++ b/m4/autobuild.m4
@@ -1,5 +1,5 @@
-# autobuild.m4 serial 5
-dnl Copyright (C) 2004, 2006, 2007 Free Software Foundation, Inc.
+# autobuild.m4 serial 7
+dnl Copyright (C) 2004, 2006, 2007, 2008 Free Software Foundation, Inc.
 dnl This file is free software; the Free Software Foundation
 dnl gives unlimited permission to copy and/or distribute it,
 dnl with or without modifications, as long as this notice is preserved.
@@ -29,7 +29,7 @@
 
   ifelse([$1],[],,[AC_MSG_NOTICE([autobuild mode... $1])])
 
-  date=`date +%Y%m%d-%H%M%S`
+  date=`TZ=UTC date +%Y%m%dT%H%M%SZ`
   if test "$?" != 0; then
     date=`date`
   fi
--- a/m4/string_h.m4
+++ b/m4/string_h.m4
@@ -5,7 +5,7 @@
 # gives unlimited permission to copy and/or distribute it,
 # with or without modifications, as long as this notice is preserved.
 
-# serial 4
+# serial 5
 
 # Written by Paul Eggert.
 
@@ -63,6 +63,7 @@
   GNULIB_MBSTOK_R=0;    AC_SUBST([GNULIB_MBSTOK_R])
   GNULIB_STRERROR=0;    AC_SUBST([GNULIB_STRERROR])
   GNULIB_STRSIGNAL=0;   AC_SUBST([GNULIB_STRSIGNAL])
+  GNULIB_STRVERSCMP=0;   AC_SUBST([GNULIB_STRVERSCMP])
   dnl Assume proper GNU behavior unless another module says otherwise.
   HAVE_DECL_MEMMEM=1;		AC_SUBST([HAVE_DECL_MEMMEM])
   HAVE_MEMPCPY=1;		AC_SUBST([HAVE_MEMPCPY])
@@ -81,6 +82,7 @@
   HAVE_DECL_STRTOK_R=1;		AC_SUBST([HAVE_DECL_STRTOK_R])
   HAVE_DECL_STRERROR=1;		AC_SUBST([HAVE_DECL_STRERROR])
   HAVE_DECL_STRSIGNAL=1;	AC_SUBST([HAVE_DECL_STRSIGNAL])
+  HAVE_STRVERSCMP=1;		AC_SUBST([HAVE_STRVERSCMP])
   REPLACE_STRERROR=0;		AC_SUBST([REPLACE_STRERROR])
   REPLACE_STRSIGNAL=0;		AC_SUBST([REPLACE_STRSIGNAL])
   REPLACE_MEMMEM=0;		AC_SUBST([REPLACE_MEMMEM])
--- a/m4/strverscmp.m4
+++ b/m4/strverscmp.m4
@@ -1,5 +1,6 @@
-# strverscmp.m4 serial 5
-dnl Copyright (C) 2002, 2005, 2006, 2007 Free Software Foundation, Inc.
+# strverscmp.m4 serial 6
+dnl Copyright (C) 2002, 2005, 2006, 2007, 2008 Free Software
+dnl Foundation, Inc.
 dnl This file is free software; the Free Software Foundation
 dnl gives unlimited permission to copy and/or distribute it,
 dnl with or without modifications, as long as this notice is preserved.
@@ -9,9 +10,11 @@
   dnl Persuade glibc <string.h> to declare strverscmp().
   AC_REQUIRE([AC_USE_SYSTEM_EXTENSIONS])
 
+  AC_REQUIRE([gl_HEADER_STRING_H_DEFAULTS])
   AC_REPLACE_FUNCS(strverscmp)
   if test $ac_cv_func_strverscmp = no; then
     gl_PREREQ_STRVERSCMP
+    HAVE_STRVERSCMP=0
   fi
 ])
 
--- a/modules/string
+++ b/modules/string
@@ -54,6 +54,7 @@
 	      -e 's|@''GNULIB_STRTOK_R''@|$(GNULIB_STRTOK_R)|g' \
 	      -e 's|@''GNULIB_STRERROR''@|$(GNULIB_STRERROR)|g' \
 	      -e 's|@''GNULIB_STRSIGNAL''@|$(GNULIB_STRSIGNAL)|g' \
+	      -e 's|@''GNULIB_STRVERSCMP''@|$(GNULIB_STRVERSCMP)|g' \
 	      -e 's|@''HAVE_DECL_MEMMEM''@|$(HAVE_DECL_MEMMEM)|g' \
 	      -e 's|@''HAVE_MEMPCPY''@|$(HAVE_MEMPCPY)|g' \
 	      -e 's|@''HAVE_DECL_MEMRCHR''@|$(HAVE_DECL_MEMRCHR)|g' \
@@ -71,6 +72,7 @@
 	      -e 's|@''HAVE_DECL_STRTOK_R''@|$(HAVE_DECL_STRTOK_R)|g' \
 	      -e 's|@''HAVE_DECL_STRERROR''@|$(HAVE_DECL_STRERROR)|g' \
 	      -e 's|@''HAVE_DECL_STRSIGNAL''@|$(HAVE_DECL_STRSIGNAL)|g' \
+	      -e 's|@''HAVE_STRVERSCMP''@|$(HAVE_STRVERSCMP)|g' \
 	      -e 's|@''REPLACE_MEMMEM''@|$(REPLACE_MEMMEM)|g' \
 	      -e 's|@''REPLACE_STRCASESTR''@|$(REPLACE_STRCASESTR)|g' \
 	      -e 's|@''REPLACE_STRSTR''@|$(REPLACE_STRSTR)|g' \
--- a/modules/strverscmp
+++ b/modules/strverscmp
@@ -2,20 +2,21 @@
 Compare strings holding version numbers.
 
 Files:
-lib/strverscmp.h
 lib/strverscmp.c
 m4/strverscmp.m4
 
 Depends-on:
 extensions
+string
 
 configure.ac:
 gl_FUNC_STRVERSCMP
+gl_STRING_MODULE_INDICATOR([strverscmp])
 
 Makefile.am:
 
 Include:
-"strverscmp.h"
+<string.h>
 
 License:
 LGPLv2+
new file mode 100644
--- /dev/null
+++ b/modules/strverscmp-tests
@@ -0,0 +1,10 @@
+Files:
+tests/test-strverscmp.c
+
+Depends-on:
+
+configure.ac:
+
+Makefile.am:
+TESTS += test-strverscmp
+check_PROGRAMS += test-strverscmp
--- a/tests/test-c-stack.c
+++ b/tests/test-c-stack.c
@@ -22,6 +22,10 @@
 #include <stdio.h>
 #include <stdlib.h>
 #if HAVE_SETRLIMIT
+/* At least FreeBSD 5.0 needs extra headers before <sys/resource.h>
+   will compile.  */
+# include <sys/types.h>
+# include <sys/time.h>
 # include <sys/resource.h>
 #endif
 
new file mode 100644
--- /dev/null
+++ b/tests/test-strverscmp.c
@@ -0,0 +1,56 @@
+/* Test of strverscmp() function.
+   Copyright (C) 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, 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.  */
+
+/* Written by Eric Blake <ebb9@byu.net>, 2008.  */
+
+#include <config.h>
+
+#include <string.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#define ASSERT(expr) \
+  do									     \
+    {									     \
+      if (!(expr))							     \
+        {								     \
+          fprintf (stderr, "%s:%d: assertion failed\n", __FILE__, __LINE__); \
+          fflush (stderr);						     \
+          abort ();							     \
+        }								     \
+    }									     \
+  while (0)
+
+int
+main (int argc, char **argv)
+{
+  ASSERT (strverscmp ("", "") == 0);
+  ASSERT (strverscmp ("a", "a") == 0);
+  ASSERT (strverscmp ("a", "b") < 0);
+  ASSERT (strverscmp ("b", "a") > 0);
+  ASSERT (strverscmp ("000", "00") < 0);
+  ASSERT (strverscmp ("00", "000") > 0);
+  ASSERT (strverscmp ("a0", "a") > 0);
+  ASSERT (strverscmp ("00", "01") < 0);
+  ASSERT (strverscmp ("01", "010") < 0);
+  ASSERT (strverscmp ("010", "09") < 0);
+  ASSERT (strverscmp ("09", "0") < 0);
+  ASSERT (strverscmp ("9", "10") < 0);
+  ASSERT (strverscmp ("0a", "0") > 0);
+  return 0;
+}