gsasl-commit
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[SCM] GNU gsasl branch, master, updated. gsasl-1-7-1-41-g7036392


From: Simon Josefsson
Subject: [SCM] GNU gsasl branch, master, updated. gsasl-1-7-1-41-g7036392
Date: Wed, 28 Mar 2012 16:44:28 +0000

This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "GNU gsasl".

http://git.savannah.gnu.org/cgit/gsasl.git/commit/?id=7036392848f055ccffa23942c0f9824d76191012

The branch, master has been updated
       via  7036392848f055ccffa23942c0f9824d76191012 (commit)
       via  675021da57146e63f2c9b7aeb8bd4fec37cc93c3 (commit)
       via  9c68dd5da9857aee4c3638617edcb1ad5ba08fb8 (commit)
       via  c640d52fb45f75f06e91039bbeefdcf2621673f7 (commit)
       via  db91b7e201ab35964826a1161dd1e2b91444451d (commit)
       via  66793f5b4c12afdcf46102640320137acd13e4cb (commit)
      from  87850b7c3cbba81edbcebe06f1d846dce5f2e7ed (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
commit 7036392848f055ccffa23942c0f9824d76191012
Author: Simon Josefsson <address@hidden>
Date:   Wed Mar 28 18:44:16 2012 +0200

    Ignore more.

commit 675021da57146e63f2c9b7aeb8bd4fec37cc93c3
Author: Simon Josefsson <address@hidden>
Date:   Wed Mar 28 16:39:02 2012 +0200

    Document new OPENID20 properties and callbacks.

commit 9c68dd5da9857aee4c3638617edcb1ad5ba08fb8
Author: Simon Josefsson <address@hidden>
Date:   Wed Mar 28 16:35:22 2012 +0200

    Add OPENID20 self-test.

commit c640d52fb45f75f06e91039bbeefdcf2621673f7
Author: Simon Josefsson <address@hidden>
Date:   Wed Mar 28 16:25:04 2012 +0200

    Fix error handling step.

commit db91b7e201ab35964826a1161dd1e2b91444451d
Author: Simon Josefsson <address@hidden>
Date:   Wed Mar 28 15:19:18 2012 +0200

    Sync example SMTP codes.

commit 66793f5b4c12afdcf46102640320137acd13e4cb
Author: Simon Josefsson <address@hidden>
Date:   Wed Mar 28 15:15:01 2012 +0200

    Update gnulib files.

-----------------------------------------------------------------------

Summary of changes:
 .gitignore             |    2 +
 doc/gsasl.texi         |   21 +++
 examples/smtp-server.c |   10 +-
 gl/Makefile.am         |    3 +-
 gl/m4/gnulib-comp.m4   |    1 -
 gl/m4/locale_h.m4      |   46 ++++++-
 gl/m4/math_h.m4        |   54 +++++++-
 gl/quote.c             |   40 ------
 gl/quote.h             |   13 ++
 gl/quotearg.c          |   25 ++++-
 gl/stdlib.in.h         |   12 ++-
 gl/string.in.h         |   23 +++-
 gl/unistr.in.h         |  174 +++++++++++++++++---------
 gl/unitypes.in.h       |   22 +++-
 gl/wchar.in.h          |   67 +++++++----
 gltests/Makefile.am    |    3 +
 gltests/fpucw.h        |    3 +-
 gltests/locale.in.h    |  105 ++++++++++++++++
 gltests/macros.h       |    5 +
 gltests/test-locale.c  |   30 +++++
 lib/build-aux/gnupload |    2 +-
 lib/gl/m4/math_h.m4    |   54 +++++++-
 lib/gl/stdlib.in.h     |   12 ++-
 lib/gl/string.in.h     |   23 +++-
 lib/gl/wchar.in.h      |   67 +++++++----
 lib/gltests/fpucw.h    |    3 +-
 lib/gltests/macros.h   |    5 +
 lib/maint.mk           |    5 +-
 lib/openid20/client.c  |   41 +++++--
 lib/openid20/server.c  |   21 ++-
 maint.mk               |    5 +-
 tests/Makefile.am      |    3 +-
 tests/openid20.c       |  326 ++++++++++++++++++++++++++++++++++++++++++++++++
 33 files changed, 1026 insertions(+), 200 deletions(-)
 delete mode 100644 gl/quote.c
 create mode 100644 tests/openid20.c

diff --git a/.gitignore b/.gitignore
index df2d054..9c772ee 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1039,6 +1039,8 @@ tests/old-md5file
 tests/old-md5file.o
 tests/old-simple
 tests/old-simple.o
+tests/openid20
+tests/openid20.o
 tests/readnz
 tests/readnz.o
 tests/saml20
diff --git a/doc/gsasl.texi b/doc/gsasl.texi
index 4768a42..71fb831 100644
--- a/doc/gsasl.texi
+++ b/doc/gsasl.texi
@@ -1577,6 +1577,14 @@ This property holds the SAML redirect URL that the 
server wants the
 client to access.  It will be available in the
 @code{GSASL_SAML20_AUTHENTICATE_IN_BROWSER} callback for the client.
 
address@hidden @code{GSASL_OPENID20_REDIRECT_URL}
+OpenID 2.0 redirect URL.
+
address@hidden @code{GSASL_OPENID20_OUTCOME_DATA}
+OpenID 2.0 authentication outcome data.  This is either the OpenID
+SREG values or a value list starting with @code{"openid.error="} to
+signal error.
+
 @end itemize
 
 Next follows a list of data properties used to trigger the callback,
@@ -1625,12 +1633,25 @@ application perform authentication.  The callback 
should return
 @code{GSASL_OK} if the user should be permitted access, and
 @code{GSASL_AUTHENTICATION_ERROR} (or another error code) otherwise.
 
address@hidden @code{GSASL_VALIDATE_OPENID20}
+
+Used by the OPENID20 mechanism on the server side to request that the
+application perform authentication.  The callback should return
address@hidden if the user should be permitted access, and
address@hidden (or another error code) otherwise.
+
 @item @code{GSASL_SAML20_AUTHENTICATE_IN_BROWSER}
 Used by the SAML20 mechanism in the client side to request that the
 client should launch the SAML redirect URL (the
 @code{GSASL_SAML20_REDIRECT_URL} property) in a browser to continue
 with authentication.
 
address@hidden @code{GSASL_OPENID20_AUTHENTICATE_IN_BROWSER}
+Used by the OPENID20 mechanism in the client side to request that the
+client should launch the OpenID redirect URL (the
address@hidden property) in a browser to continue
+with authentication.
+
 @end itemize
 
 
diff --git a/examples/smtp-server.c b/examples/smtp-server.c
index 8d6f45d..dc33706 100644
--- a/examples/smtp-server.c
+++ b/examples/smtp-server.c
@@ -66,9 +66,9 @@ gettrimline (char **line, size_t * n, FILE * fh)
        (*line)[strlen (*line) - 1] = '\0';
       if ((*line)[strlen (*line) - 1] == '\r')
        (*line)[strlen (*line) - 1] = '\0';
-    }
 
-  printf ("C: %s\n", *line);
+      printf ("C: %s\n", *line);
+    }
 
   return s;
 }
@@ -197,6 +197,8 @@ main (int argc, char *argv[])
   int yes = 1;
   Gsasl *ctx;
 
+  setvbuf (stdout, NULL, _IONBF, 0);
+
   rc = gsasl_init (&ctx);
   if (rc < 0)
     {
@@ -204,8 +206,8 @@ main (int argc, char *argv[])
       exit (EXIT_FAILURE);
     }
 
-  printf ("smtp-server [gsasl header %s library %s]\n",
-         GSASL_VERSION, gsasl_check_version (NULL));
+  printf ("%s [gsasl header %s library %s]\n",
+         argv[0], GSASL_VERSION, gsasl_check_version (NULL));
 
   gsasl_callback_set (ctx, callback);
 
diff --git a/gl/Makefile.am b/gl/Makefile.am
index 50e1728..4d85046 100644
--- a/gl/Makefile.am
+++ b/gl/Makefile.am
@@ -767,7 +767,6 @@ libgl_la_SOURCES += progname.h progname.c
 
 ## begin gnulib module quote
 
-libgl_la_SOURCES += quote.c
 
 EXTRA_DIST += quote.h
 
@@ -777,7 +776,7 @@ EXTRA_DIST += quote.h
 
 libgl_la_SOURCES += quotearg.c
 
-EXTRA_DIST += quotearg.h
+EXTRA_DIST += quote.h quotearg.h
 
 ## end   gnulib module quotearg
 
diff --git a/gl/m4/gnulib-comp.m4 b/gl/m4/gnulib-comp.m4
index 9f4511d..3329ea8 100644
--- a/gl/m4/gnulib-comp.m4
+++ b/gl/m4/gnulib-comp.m4
@@ -1063,7 +1063,6 @@ AC_DEFUN([gl_FILE_LIST], [
   lib/printf-parse.h
   lib/progname.c
   lib/progname.h
-  lib/quote.c
   lib/quote.h
   lib/quotearg.c
   lib/quotearg.h
diff --git a/gl/m4/locale_h.m4 b/gl/m4/locale_h.m4
index 4289587..fb72e4e 100644
--- a/gl/m4/locale_h.m4
+++ b/gl/m4/locale_h.m4
@@ -1,4 +1,4 @@
-# locale_h.m4 serial 14
+# locale_h.m4 serial 18
 dnl Copyright (C) 2007, 2009-2012 Free Software Foundation, Inc.
 dnl This file is free software; the Free Software Foundation
 dnl gives unlimited permission to copy and/or distribute it,
@@ -10,18 +10,29 @@ AC_DEFUN([gl_LOCALE_H],
   dnl once only, before all statements that occur in other macros.
   AC_REQUIRE([gl_LOCALE_H_DEFAULTS])
 
-  dnl Persuade glibc <locale.h> to define locale_t.
+  dnl Persuade glibc <locale.h> to define locale_t and the int_p_*, int_n_*
+  dnl members of 'struct lconv'.
   AC_REQUIRE([gl_USE_SYSTEM_EXTENSIONS])
 
   dnl If <stddef.h> is replaced, then <locale.h> must also be replaced.
   AC_REQUIRE([gl_STDDEF_H])
 
+  dnl Solaris 11 2011-11 defines the int_p_*, int_n_* members of 'struct lconv'
+  dnl only if _LCONV_C99 is defined.
+  AC_REQUIRE([AC_CANONICAL_HOST])
+  case "$host_os" in
+    solaris*)
+      AC_DEFINE([_LCONV_C99], [1], [Define to 1 on Solaris.])
+      ;;
+  esac
+
   AC_CACHE_CHECK([whether locale.h conforms to POSIX:2001],
     [gl_cv_header_locale_h_posix2001],
     [AC_COMPILE_IFELSE(
        [AC_LANG_PROGRAM(
           [[#include <locale.h>
-            int x = LC_MESSAGES;]],
+            int x = LC_MESSAGES;
+            int y = sizeof (((struct lconv *) 0)->decimal_point);]],
           [[]])],
        [gl_cv_header_locale_h_posix2001=yes],
        [gl_cv_header_locale_h_posix2001=no])])
@@ -54,6 +65,26 @@ AC_DEFUN([gl_LOCALE_H],
   fi
   AC_SUBST([HAVE_XLOCALE_H])
 
+  dnl Check whether 'struct lconv' is complete.
+  dnl Bionic libc's 'struct lconv' is just a dummy.
+  dnl On OpenBSD 4.9, HP-UX 11, IRIX 6.5, OSF/1 5.1, Solaris 9, Cygwin 1.5.x,
+  dnl mingw, MSVC 9, it lacks the int_p_* and int_n_* members.
+  AC_CACHE_CHECK([whether struct lconv is properly defined],
+    [gl_cv_sys_struct_lconv_ok],
+    [AC_COMPILE_IFELSE(
+       [AC_LANG_PROGRAM(
+          [[#include <locale.h>
+            struct lconv l;
+            int x = sizeof (l.decimal_point);
+            int y = sizeof (l.int_p_cs_precedes);]],
+          [[]])],
+       [gl_cv_sys_struct_lconv_ok=yes],
+       [gl_cv_sys_struct_lconv_ok=no])
+    ])
+  if test $gl_cv_sys_struct_lconv_ok = no; then
+    REPLACE_STRUCT_LCONV=1
+  fi
+
   dnl <locale.h> is always overridden, because of GNULIB_POSIXCHECK.
   gl_NEXT_HEADERS([locale.h])
 
@@ -79,10 +110,13 @@ AC_DEFUN([gl_LOCALE_MODULE_INDICATOR],
 
 AC_DEFUN([gl_LOCALE_H_DEFAULTS],
 [
+  GNULIB_LOCALECONV=0; AC_SUBST([GNULIB_LOCALECONV])
   GNULIB_SETLOCALE=0;  AC_SUBST([GNULIB_SETLOCALE])
   GNULIB_DUPLOCALE=0;  AC_SUBST([GNULIB_DUPLOCALE])
   dnl Assume proper GNU behavior unless another module says otherwise.
-  HAVE_DUPLOCALE=1;    AC_SUBST([HAVE_DUPLOCALE])
-  REPLACE_SETLOCALE=0; AC_SUBST([REPLACE_SETLOCALE])
-  REPLACE_DUPLOCALE=0; AC_SUBST([REPLACE_DUPLOCALE])
+  HAVE_DUPLOCALE=1;       AC_SUBST([HAVE_DUPLOCALE])
+  REPLACE_LOCALECONV=0;   AC_SUBST([REPLACE_LOCALECONV])
+  REPLACE_SETLOCALE=0;    AC_SUBST([REPLACE_SETLOCALE])
+  REPLACE_DUPLOCALE=0;    AC_SUBST([REPLACE_DUPLOCALE])
+  REPLACE_STRUCT_LCONV=0; AC_SUBST([REPLACE_STRUCT_LCONV])
 ])
diff --git a/gl/m4/math_h.m4 b/gl/m4/math_h.m4
index a5a71f2..ff1654e 100644
--- a/gl/m4/math_h.m4
+++ b/gl/m4/math_h.m4
@@ -1,4 +1,4 @@
-# math_h.m4 serial 79
+# math_h.m4 serial 104
 dnl Copyright (C) 2007-2012 Free Software Foundation, Inc.
 dnl This file is free software; the Free Software Foundation
 dnl gives unlimited permission to copy and/or distribute it,
@@ -41,9 +41,12 @@ AC_DEFUN([gl_MATH_H],
   gl_WARN_ON_USE_PREPARE([[#include <math.h>]],
     [acosf acosl asinf asinl atanf atanl
      cbrt cbrtf cbrtl ceilf ceill copysign copysignf copysignl cosf cosl coshf
-     expf expl fabsf fabsl floorf floorl fma fmaf fmal
+     expf expl exp2 exp2f exp2l expm1 expm1f expm1l
+     fabsf fabsl floorf floorl fma fmaf fmal
      fmod fmodf fmodl frexpf frexpl hypotf hypotl
-     ldexpf ldexpl logb logf logl log10f log10l modf modff modfl powf
+     ldexpf ldexpl
+     logb log logf logl log10f log10l log1p log1pf log1pl log2 log2f log2l
+     modf modff modfl powf
      remainder remainderf remainderl
      rint rintf rintl round roundf roundl sinf sinl sinhf sqrtf sqrtl
      tanf tanl tanhf trunc truncf truncl])
@@ -81,6 +84,12 @@ AC_DEFUN([gl_MATH_H_DEFAULTS],
   GNULIB_COSHF=0;      AC_SUBST([GNULIB_COSHF])
   GNULIB_EXPF=0;       AC_SUBST([GNULIB_EXPF])
   GNULIB_EXPL=0;       AC_SUBST([GNULIB_EXPL])
+  GNULIB_EXP2=0;       AC_SUBST([GNULIB_EXP2])
+  GNULIB_EXP2F=0;      AC_SUBST([GNULIB_EXP2F])
+  GNULIB_EXP2L=0;      AC_SUBST([GNULIB_EXP2L])
+  GNULIB_EXPM1=0;      AC_SUBST([GNULIB_EXPM1])
+  GNULIB_EXPM1F=0;     AC_SUBST([GNULIB_EXPM1F])
+  GNULIB_EXPM1L=0;     AC_SUBST([GNULIB_EXPM1L])
   GNULIB_FABSF=0;      AC_SUBST([GNULIB_FABSF])
   GNULIB_FABSL=0;      AC_SUBST([GNULIB_FABSL])
   GNULIB_FLOOR=0;      AC_SUBST([GNULIB_FLOOR])
@@ -107,10 +116,17 @@ AC_DEFUN([gl_MATH_H_DEFAULTS],
   GNULIB_LDEXPF=0;     AC_SUBST([GNULIB_LDEXPF])
   GNULIB_LDEXPL=0;     AC_SUBST([GNULIB_LDEXPL])
   GNULIB_LOGB=0;       AC_SUBST([GNULIB_LOGB])
+  GNULIB_LOG=0;        AC_SUBST([GNULIB_LOG])
   GNULIB_LOGF=0;       AC_SUBST([GNULIB_LOGF])
   GNULIB_LOGL=0;       AC_SUBST([GNULIB_LOGL])
   GNULIB_LOG10F=0;     AC_SUBST([GNULIB_LOG10F])
   GNULIB_LOG10L=0;     AC_SUBST([GNULIB_LOG10L])
+  GNULIB_LOG1P=0;      AC_SUBST([GNULIB_LOG1P])
+  GNULIB_LOG1PF=0;     AC_SUBST([GNULIB_LOG1PF])
+  GNULIB_LOG1PL=0;     AC_SUBST([GNULIB_LOG1PL])
+  GNULIB_LOG2=0;       AC_SUBST([GNULIB_LOG2])
+  GNULIB_LOG2F=0;      AC_SUBST([GNULIB_LOG2F])
+  GNULIB_LOG2L=0;      AC_SUBST([GNULIB_LOG2L])
   GNULIB_MODF=0;       AC_SUBST([GNULIB_MODF])
   GNULIB_MODFF=0;      AC_SUBST([GNULIB_MODFF])
   GNULIB_MODFL=0;      AC_SUBST([GNULIB_MODFL])
@@ -148,13 +164,14 @@ AC_DEFUN([gl_MATH_H_DEFAULTS],
   HAVE_CBRTF=1;                AC_SUBST([HAVE_CBRTF])
   HAVE_CBRTL=1;                AC_SUBST([HAVE_CBRTL])
   HAVE_COPYSIGN=1;             AC_SUBST([HAVE_COPYSIGN])
-  HAVE_COPYSIGNF=1;            AC_SUBST([HAVE_COPYSIGNF])
   HAVE_COPYSIGNL=1;            AC_SUBST([HAVE_COPYSIGNL])
   HAVE_COSF=1;                 AC_SUBST([HAVE_COSF])
   HAVE_COSL=1;                 AC_SUBST([HAVE_COSL])
   HAVE_COSHF=1;                AC_SUBST([HAVE_COSHF])
   HAVE_EXPF=1;                 AC_SUBST([HAVE_EXPF])
   HAVE_EXPL=1;                 AC_SUBST([HAVE_EXPL])
+  HAVE_EXPM1=1;                AC_SUBST([HAVE_EXPM1])
+  HAVE_EXPM1F=1;               AC_SUBST([HAVE_EXPM1F])
   HAVE_FABSF=1;                AC_SUBST([HAVE_FABSF])
   HAVE_FABSL=1;                AC_SUBST([HAVE_FABSL])
   HAVE_FMA=1;                  AC_SUBST([HAVE_FMA])
@@ -173,14 +190,15 @@ AC_DEFUN([gl_MATH_H_DEFAULTS],
   HAVE_LOGL=1;                 AC_SUBST([HAVE_LOGL])
   HAVE_LOG10F=1;               AC_SUBST([HAVE_LOG10F])
   HAVE_LOG10L=1;               AC_SUBST([HAVE_LOG10L])
+  HAVE_LOG1P=1;                AC_SUBST([HAVE_LOG1P])
+  HAVE_LOG1PF=1;               AC_SUBST([HAVE_LOG1PF])
+  HAVE_LOG1PL=1;               AC_SUBST([HAVE_LOG1PL])
   HAVE_MODFF=1;                AC_SUBST([HAVE_MODFF])
   HAVE_MODFL=1;                AC_SUBST([HAVE_MODFL])
   HAVE_POWF=1;                 AC_SUBST([HAVE_POWF])
   HAVE_REMAINDER=1;            AC_SUBST([HAVE_REMAINDER])
   HAVE_REMAINDERF=1;           AC_SUBST([HAVE_REMAINDERF])
-  HAVE_REMAINDERL=1;           AC_SUBST([HAVE_REMAINDERL])
   HAVE_RINT=1;                 AC_SUBST([HAVE_RINT])
-  HAVE_RINTF=1;                AC_SUBST([HAVE_RINTF])
   HAVE_RINTL=1;                AC_SUBST([HAVE_RINTL])
   HAVE_SINF=1;                 AC_SUBST([HAVE_SINF])
   HAVE_SINL=1;                 AC_SUBST([HAVE_SINL])
@@ -197,8 +215,13 @@ AC_DEFUN([gl_MATH_H_DEFAULTS],
   HAVE_DECL_CBRTL=1;           AC_SUBST([HAVE_DECL_CBRTL])
   HAVE_DECL_CEILF=1;           AC_SUBST([HAVE_DECL_CEILF])
   HAVE_DECL_CEILL=1;           AC_SUBST([HAVE_DECL_CEILL])
+  HAVE_DECL_COPYSIGNF=1;       AC_SUBST([HAVE_DECL_COPYSIGNF])
   HAVE_DECL_COSL=1;            AC_SUBST([HAVE_DECL_COSL])
   HAVE_DECL_EXPL=1;            AC_SUBST([HAVE_DECL_EXPL])
+  HAVE_DECL_EXP2=1;            AC_SUBST([HAVE_DECL_EXP2])
+  HAVE_DECL_EXP2F=1;           AC_SUBST([HAVE_DECL_EXP2F])
+  HAVE_DECL_EXP2L=1;           AC_SUBST([HAVE_DECL_EXP2L])
+  HAVE_DECL_EXPM1L=1;          AC_SUBST([HAVE_DECL_EXPM1L])
   HAVE_DECL_FLOORF=1;          AC_SUBST([HAVE_DECL_FLOORF])
   HAVE_DECL_FLOORL=1;          AC_SUBST([HAVE_DECL_FLOORL])
   HAVE_DECL_FREXPL=1;          AC_SUBST([HAVE_DECL_FREXPL])
@@ -206,7 +229,12 @@ AC_DEFUN([gl_MATH_H_DEFAULTS],
   HAVE_DECL_LOGB=1;            AC_SUBST([HAVE_DECL_LOGB])
   HAVE_DECL_LOGL=1;            AC_SUBST([HAVE_DECL_LOGL])
   HAVE_DECL_LOG10L=1;          AC_SUBST([HAVE_DECL_LOG10L])
+  HAVE_DECL_LOG2=1;            AC_SUBST([HAVE_DECL_LOG2])
+  HAVE_DECL_LOG2F=1;           AC_SUBST([HAVE_DECL_LOG2F])
+  HAVE_DECL_LOG2L=1;           AC_SUBST([HAVE_DECL_LOG2L])
   HAVE_DECL_REMAINDER=1;       AC_SUBST([HAVE_DECL_REMAINDER])
+  HAVE_DECL_REMAINDERL=1;      AC_SUBST([HAVE_DECL_REMAINDERL])
+  HAVE_DECL_RINTF=1;           AC_SUBST([HAVE_DECL_RINTF])
   HAVE_DECL_ROUND=1;           AC_SUBST([HAVE_DECL_ROUND])
   HAVE_DECL_ROUNDF=1;          AC_SUBST([HAVE_DECL_ROUNDF])
   HAVE_DECL_ROUNDL=1;          AC_SUBST([HAVE_DECL_ROUNDL])
@@ -221,6 +249,10 @@ AC_DEFUN([gl_MATH_H_DEFAULTS],
   REPLACE_CEIL=0;              AC_SUBST([REPLACE_CEIL])
   REPLACE_CEILF=0;             AC_SUBST([REPLACE_CEILF])
   REPLACE_CEILL=0;             AC_SUBST([REPLACE_CEILL])
+  REPLACE_EXPM1=0;             AC_SUBST([REPLACE_EXPM1])
+  REPLACE_EXPM1F=0;            AC_SUBST([REPLACE_EXPM1F])
+  REPLACE_EXP2=0;              AC_SUBST([REPLACE_EXP2])
+  REPLACE_EXP2L=0;             AC_SUBST([REPLACE_EXP2L])
   REPLACE_FABSL=0;             AC_SUBST([REPLACE_FABSL])
   REPLACE_FLOOR=0;             AC_SUBST([REPLACE_FLOOR])
   REPLACE_FLOORF=0;            AC_SUBST([REPLACE_FLOORF])
@@ -242,6 +274,15 @@ AC_DEFUN([gl_MATH_H_DEFAULTS],
   REPLACE_ISINF=0;             AC_SUBST([REPLACE_ISINF])
   REPLACE_ISNAN=0;             AC_SUBST([REPLACE_ISNAN])
   REPLACE_LDEXPL=0;            AC_SUBST([REPLACE_LDEXPL])
+  REPLACE_LOG=0;               AC_SUBST([REPLACE_LOG])
+  REPLACE_LOGF=0;              AC_SUBST([REPLACE_LOGF])
+  REPLACE_LOGL=0;              AC_SUBST([REPLACE_LOGL])
+  REPLACE_LOG1P=0;             AC_SUBST([REPLACE_LOG1P])
+  REPLACE_LOG1PF=0;            AC_SUBST([REPLACE_LOG1PF])
+  REPLACE_LOG1PL=0;            AC_SUBST([REPLACE_LOG1PL])
+  REPLACE_LOG2=0;              AC_SUBST([REPLACE_LOG2])
+  REPLACE_LOG2F=0;             AC_SUBST([REPLACE_LOG2F])
+  REPLACE_LOG2L=0;             AC_SUBST([REPLACE_LOG2L])
   REPLACE_MODF=0;              AC_SUBST([REPLACE_MODF])
   REPLACE_MODFF=0;             AC_SUBST([REPLACE_MODFF])
   REPLACE_MODFL=0;             AC_SUBST([REPLACE_MODFL])
@@ -254,6 +295,7 @@ AC_DEFUN([gl_MATH_H_DEFAULTS],
   REPLACE_ROUNDL=0;            AC_SUBST([REPLACE_ROUNDL])
   REPLACE_SIGNBIT=0;           AC_SUBST([REPLACE_SIGNBIT])
   REPLACE_SIGNBIT_USING_GCC=0; AC_SUBST([REPLACE_SIGNBIT_USING_GCC])
+  REPLACE_SQRTL=0;             AC_SUBST([REPLACE_SQRTL])
   REPLACE_TRUNC=0;             AC_SUBST([REPLACE_TRUNC])
   REPLACE_TRUNCF=0;            AC_SUBST([REPLACE_TRUNCF])
   REPLACE_TRUNCL=0;            AC_SUBST([REPLACE_TRUNCL])
diff --git a/gl/quote.c b/gl/quote.c
deleted file mode 100644
index b46fd83..0000000
--- a/gl/quote.c
+++ /dev/null
@@ -1,40 +0,0 @@
-/* quote.c - quote arguments for output
-
-   Copyright (C) 1998-2001, 2003, 2005-2006, 2009-2012 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 <address@hidden> */
-
-#include <config.h>
-
-#include "quotearg.h"
-#include "quote.h"
-
-/* Return an unambiguous printable representation of NAME,
-   allocated in slot N, suitable for diagnostics.  */
-char const *
-quote_n (int n, char const *name)
-{
-  return quotearg_n_style (n, locale_quoting_style, name);
-}
-
-/* Return an unambiguous printable representation of NAME,
-   suitable for diagnostics.  */
-char const *
-quote (char const *name)
-{
-  return quote_n (0, name);
-}
diff --git a/gl/quote.h b/gl/quote.h
index 140908b..b30b166 100644
--- a/gl/quote.h
+++ b/gl/quote.h
@@ -15,6 +15,19 @@
    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
 
+#ifndef QUOTE_H_
+# define QUOTE_H_ 1
 
+/* The quoting options used by quote_n and quote.  Its type is incomplete,
+   so it's useful only in expressions like '&quote_quoting_options'.  */
+extern struct quoting_options quote_quoting_options;
+
+/* Return an unambiguous printable representation of NAME,
+   allocated in slot N, suitable for diagnostics.  */
 char const *quote_n (int n, char const *name);
+
+/* Return an unambiguous printable representation of NAME,
+   suitable for diagnostics.  */
 char const *quote (char const *name);
+
+#endif /* !QUOTE_H_ */
diff --git a/gl/quotearg.c b/gl/quotearg.c
index c37aa35..1ea583d 100644
--- a/gl/quotearg.c
+++ b/gl/quotearg.c
@@ -27,6 +27,7 @@
 #include <config.h>
 
 #include "quotearg.h"
+#include "quote.h"
 
 #include "xalloc.h"
 #include "c-strcaseeq.h"
@@ -177,7 +178,7 @@ set_custom_quoting (struct quoting_options *o,
 static struct quoting_options /* NOT PURE!! */
 quoting_options_from_style (enum quoting_style style)
 {
-  struct quoting_options o = { 0 };
+  struct quoting_options o = { 0, 0, { 0 }, NULL, NULL };
   if (style == custom_quoting_style)
     abort ();
   o.style = style;
@@ -926,3 +927,25 @@ quotearg_custom_mem (char const *left_quote, char const 
*right_quote,
   return quotearg_n_custom_mem (0, left_quote, right_quote, arg,
                                 argsize);
 }
+
+
+/* The quoting option used by quote_n and quote.  */
+struct quoting_options quote_quoting_options =
+  {
+    locale_quoting_style,
+    0,
+    { 0 },
+    NULL, NULL
+  };
+
+char const *
+quote_n (int n, char const *name)
+{
+  return quotearg_n_options (n, name, SIZE_MAX, &quote_quoting_options);
+}
+
+char const *
+quote (char const *name)
+{
+  return quote_n (0, name);
+}
diff --git a/gl/stdlib.in.h b/gl/stdlib.in.h
index e92a614..b546133 100644
--- a/gl/stdlib.in.h
+++ b/gl/stdlib.in.h
@@ -94,6 +94,14 @@ struct random_data
 # include <unistd.h>
 #endif
 
+/* The __attribute__ feature is available in gcc versions 2.5 and later.
+   The attribute __pure__ was added in gcc 2.96.  */
+#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 96)
+# define _GL_ATTRIBUTE_PURE __attribute__ ((__pure__))
+#else
+# define _GL_ATTRIBUTE_PURE /* empty */
+#endif
+
 /* The definition of _Noreturn is copied here.  */
 
 /* The definitions of _GL_FUNCDECL_RPL etc. are copied here.  */
@@ -138,7 +146,9 @@ _GL_WARN_ON_USE (_Exit, "_Exit is unportable - "
 /* Parse a signed decimal integer.
    Returns the value of the integer.  Errors are not detected.  */
 # if address@hidden@
-_GL_FUNCDECL_SYS (atoll, long long, (const char *string) _GL_ARG_NONNULL 
((1)));
+_GL_FUNCDECL_SYS (atoll, long long, (const char *string)
+                                    _GL_ATTRIBUTE_PURE
+                                    _GL_ARG_NONNULL ((1)));
 # endif
 _GL_CXXALIAS_SYS (atoll, long long, (const char *string));
 _GL_CXXALIASWARN (atoll);
diff --git a/gl/string.in.h b/gl/string.in.h
index cad18db..f8d7520 100644
--- a/gl/string.in.h
+++ b/gl/string.in.h
@@ -724,10 +724,14 @@ _GL_WARN_ON_USE (strtok_r, "strtok_r is unportable - "
 #  if !(defined __cplusplus && defined GNULIB_NAMESPACE)
 #   define mbslen rpl_mbslen
 #  endif
-_GL_FUNCDECL_RPL (mbslen, size_t, (const char *string) _GL_ARG_NONNULL ((1)));
+_GL_FUNCDECL_RPL (mbslen, size_t, (const char *string)
+                                  _GL_ATTRIBUTE_PURE
+                                  _GL_ARG_NONNULL ((1)));
 _GL_CXXALIAS_RPL (mbslen, size_t, (const char *string));
 # else
-_GL_FUNCDECL_SYS (mbslen, size_t, (const char *string) _GL_ARG_NONNULL ((1)));
+_GL_FUNCDECL_SYS (mbslen, size_t, (const char *string)
+                                  _GL_ATTRIBUTE_PURE
+                                  _GL_ARG_NONNULL ((1)));
 _GL_CXXALIAS_SYS (mbslen, size_t, (const char *string));
 # endif
 _GL_CXXALIASWARN (mbslen);
@@ -737,6 +741,7 @@ _GL_CXXALIASWARN (mbslen);
 /* Return the number of multibyte characters in the character string starting
    at STRING and ending at STRING + LEN.  */
 _GL_EXTERN_C size_t mbsnlen (const char *string, size_t len)
+     _GL_ATTRIBUTE_PURE
      _GL_ARG_NONNULL ((1));
 #endif
 
@@ -750,10 +755,12 @@ _GL_EXTERN_C size_t mbsnlen (const char *string, size_t 
len)
 #   define mbschr rpl_mbschr /* avoid collision with HP-UX function */
 #  endif
 _GL_FUNCDECL_RPL (mbschr, char *, (const char *string, int c)
+                                  _GL_ATTRIBUTE_PURE
                                   _GL_ARG_NONNULL ((1)));
 _GL_CXXALIAS_RPL (mbschr, char *, (const char *string, int c));
 # else
 _GL_FUNCDECL_SYS (mbschr, char *, (const char *string, int c)
+                                  _GL_ATTRIBUTE_PURE
                                   _GL_ARG_NONNULL ((1)));
 _GL_CXXALIAS_SYS (mbschr, char *, (const char *string, int c));
 # endif
@@ -770,10 +777,12 @@ _GL_CXXALIASWARN (mbschr);
 #   define mbsrchr rpl_mbsrchr /* avoid collision with system function */
 #  endif
 _GL_FUNCDECL_RPL (mbsrchr, char *, (const char *string, int c)
+                                   _GL_ATTRIBUTE_PURE
                                    _GL_ARG_NONNULL ((1)));
 _GL_CXXALIAS_RPL (mbsrchr, char *, (const char *string, int c));
 # else
 _GL_FUNCDECL_SYS (mbsrchr, char *, (const char *string, int c)
+                                   _GL_ATTRIBUTE_PURE
                                    _GL_ARG_NONNULL ((1)));
 _GL_CXXALIAS_SYS (mbsrchr, char *, (const char *string, int c));
 # endif
@@ -786,6 +795,7 @@ _GL_CXXALIASWARN (mbsrchr);
    Unlike strstr(), this function works correctly in multibyte locales with
    encodings different from UTF-8.  */
 _GL_EXTERN_C char * mbsstr (const char *haystack, const char *needle)
+     _GL_ATTRIBUTE_PURE
      _GL_ARG_NONNULL ((1, 2));
 #endif
 
@@ -797,6 +807,7 @@ _GL_EXTERN_C char * mbsstr (const char *haystack, const 
char *needle)
    different lengths!
    Unlike strcasecmp(), this function works correctly in multibyte locales.  */
 _GL_EXTERN_C int mbscasecmp (const char *s1, const char *s2)
+     _GL_ATTRIBUTE_PURE
      _GL_ARG_NONNULL ((1, 2));
 #endif
 
@@ -811,6 +822,7 @@ _GL_EXTERN_C int mbscasecmp (const char *s1, const char *s2)
    Unlike strncasecmp(), this function works correctly in multibyte locales.
    But beware that N is not a byte count but a character count!  */
 _GL_EXTERN_C int mbsncasecmp (const char *s1, const char *s2, size_t n)
+     _GL_ATTRIBUTE_PURE
      _GL_ARG_NONNULL ((1, 2));
 #endif
 
@@ -824,6 +836,7 @@ _GL_EXTERN_C int mbsncasecmp (const char *s1, const char 
*s2, size_t n)
    Unlike strncasecmp(), this function works correctly in multibyte
    locales.  */
 _GL_EXTERN_C char * mbspcasecmp (const char *string, const char *prefix)
+     _GL_ATTRIBUTE_PURE
      _GL_ARG_NONNULL ((1, 2));
 #endif
 
@@ -834,6 +847,7 @@ _GL_EXTERN_C char * mbspcasecmp (const char *string, const 
char *prefix)
    strlen (haystack) < strlen (needle) !
    Unlike strcasestr(), this function works correctly in multibyte locales.  */
 _GL_EXTERN_C char * mbscasestr (const char *haystack, const char *needle)
+     _GL_ATTRIBUTE_PURE
      _GL_ARG_NONNULL ((1, 2));
 #endif
 
@@ -844,6 +858,7 @@ _GL_EXTERN_C char * mbscasestr (const char *haystack, const 
char *needle)
    if none exists.
    Unlike strcspn(), this function works correctly in multibyte locales.  */
 _GL_EXTERN_C size_t mbscspn (const char *string, const char *accept)
+     _GL_ATTRIBUTE_PURE
      _GL_ARG_NONNULL ((1, 2));
 #endif
 
@@ -857,10 +872,12 @@ _GL_EXTERN_C size_t mbscspn (const char *string, const 
char *accept)
 #   define mbspbrk rpl_mbspbrk /* avoid collision with HP-UX function */
 #  endif
 _GL_FUNCDECL_RPL (mbspbrk, char *, (const char *string, const char *accept)
+                                   _GL_ATTRIBUTE_PURE
                                    _GL_ARG_NONNULL ((1, 2)));
 _GL_CXXALIAS_RPL (mbspbrk, char *, (const char *string, const char *accept));
 # else
 _GL_FUNCDECL_SYS (mbspbrk, char *, (const char *string, const char *accept)
+                                   _GL_ATTRIBUTE_PURE
                                    _GL_ARG_NONNULL ((1, 2)));
 _GL_CXXALIAS_SYS (mbspbrk, char *, (const char *string, const char *accept));
 # endif
@@ -874,6 +891,7 @@ _GL_CXXALIASWARN (mbspbrk);
    if none exists.
    Unlike strspn(), this function works correctly in multibyte locales.  */
 _GL_EXTERN_C size_t mbsspn (const char *string, const char *reject)
+     _GL_ATTRIBUTE_PURE
      _GL_ARG_NONNULL ((1, 2));
 #endif
 
@@ -993,6 +1011,7 @@ _GL_WARN_ON_USE (strsignal, "strsignal is unportable - "
 #if @GNULIB_STRVERSCMP@
 # if address@hidden@
 _GL_FUNCDECL_SYS (strverscmp, int, (const char *, const char *)
+                                   _GL_ATTRIBUTE_PURE
                                    _GL_ARG_NONNULL ((1, 2)));
 # endif
 _GL_CXXALIAS_SYS (strverscmp, int, (const char *, const char *));
diff --git a/gl/unistr.in.h b/gl/unistr.in.h
index 479075e..5cda3f5 100644
--- a/gl/unistr.in.h
+++ b/gl/unistr.in.h
@@ -66,17 +66,20 @@ extern "C" {
 /* Check whether an UTF-8 string is well-formed.
    Return NULL if valid, or a pointer to the first invalid unit otherwise.  */
 extern const uint8_t *
-       u8_check (const uint8_t *s, size_t n);
+       u8_check (const uint8_t *s, size_t n)
+       _UC_ATTRIBUTE_PURE;
 
 /* Check whether an UTF-16 string is well-formed.
    Return NULL if valid, or a pointer to the first invalid unit otherwise.  */
 extern const uint16_t *
-       u16_check (const uint16_t *s, size_t n);
+       u16_check (const uint16_t *s, size_t n)
+       _UC_ATTRIBUTE_PURE;
 
 /* Check whether an UCS-4 string is well-formed.
    Return NULL if valid, or a pointer to the first invalid unit otherwise.  */
 extern const uint32_t *
-       u32_check (const uint32_t *s, size_t n);
+       u32_check (const uint32_t *s, size_t n)
+       _UC_ATTRIBUTE_PURE;
 
 
 /* Elementary string conversions.  */
@@ -119,11 +122,14 @@ extern uint16_t *
    failure.  */
 /* Similar to mblen(), except that s must not be NULL.  */
 extern int
-       u8_mblen (const uint8_t *s, size_t n);
+       u8_mblen (const uint8_t *s, size_t n)
+       _UC_ATTRIBUTE_PURE;
 extern int
-       u16_mblen (const uint16_t *s, size_t n);
+       u16_mblen (const uint16_t *s, size_t n)
+       _UC_ATTRIBUTE_PURE;
 extern int
-       u32_mblen (const uint32_t *s, size_t n);
+       u32_mblen (const uint32_t *s, size_t n)
+       _UC_ATTRIBUTE_PURE;
 
 /* Return the length (number of units) of the first character in S, putting
    its 'ucs4_t' representation in *PUC.  Upon failure, *PUC is set to 0xfffd,
@@ -400,38 +406,50 @@ extern uint32_t *
 /* Compare S1 and S2, each of length N.  */
 /* Similar to memcmp().  */
 extern int
-       u8_cmp (const uint8_t *s1, const uint8_t *s2, size_t n);
+       u8_cmp (const uint8_t *s1, const uint8_t *s2, size_t n)
+       _UC_ATTRIBUTE_PURE;
 extern int
-       u16_cmp (const uint16_t *s1, const uint16_t *s2, size_t n);
+       u16_cmp (const uint16_t *s1, const uint16_t *s2, size_t n)
+       _UC_ATTRIBUTE_PURE;
 extern int
-       u32_cmp (const uint32_t *s1, const uint32_t *s2, size_t n);
+       u32_cmp (const uint32_t *s1, const uint32_t *s2, size_t n)
+       _UC_ATTRIBUTE_PURE;
 
 /* Compare S1 and S2.  */
 /* Similar to the gnulib function memcmp2().  */
 extern int
-       u8_cmp2 (const uint8_t *s1, size_t n1, const uint8_t *s2, size_t n2);
+       u8_cmp2 (const uint8_t *s1, size_t n1, const uint8_t *s2, size_t n2)
+       _UC_ATTRIBUTE_PURE;
 extern int
-       u16_cmp2 (const uint16_t *s1, size_t n1, const uint16_t *s2, size_t n2);
+       u16_cmp2 (const uint16_t *s1, size_t n1, const uint16_t *s2, size_t n2)
+       _UC_ATTRIBUTE_PURE;
 extern int
-       u32_cmp2 (const uint32_t *s1, size_t n1, const uint32_t *s2, size_t n2);
+       u32_cmp2 (const uint32_t *s1, size_t n1, const uint32_t *s2, size_t n2)
+       _UC_ATTRIBUTE_PURE;
 
 /* Search the string at S for UC.  */
 /* Similar to memchr().  */
 extern uint8_t *
-       u8_chr (const uint8_t *s, size_t n, ucs4_t uc);
+       u8_chr (const uint8_t *s, size_t n, ucs4_t uc)
+       _UC_ATTRIBUTE_PURE;
 extern uint16_t *
-       u16_chr (const uint16_t *s, size_t n, ucs4_t uc);
+       u16_chr (const uint16_t *s, size_t n, ucs4_t uc)
+       _UC_ATTRIBUTE_PURE;
 extern uint32_t *
-       u32_chr (const uint32_t *s, size_t n, ucs4_t uc);
+       u32_chr (const uint32_t *s, size_t n, ucs4_t uc)
+       _UC_ATTRIBUTE_PURE;
 
 /* Count the number of Unicode characters in the N units from S.  */
 /* Similar to mbsnlen().  */
 extern size_t
-       u8_mbsnlen (const uint8_t *s, size_t n);
+       u8_mbsnlen (const uint8_t *s, size_t n)
+       _UC_ATTRIBUTE_PURE;
 extern size_t
-       u16_mbsnlen (const uint16_t *s, size_t n);
+       u16_mbsnlen (const uint16_t *s, size_t n)
+       _UC_ATTRIBUTE_PURE;
 extern size_t
-       u32_mbsnlen (const uint32_t *s, size_t n);
+       u32_mbsnlen (const uint32_t *s, size_t n)
+       _UC_ATTRIBUTE_PURE;
 
 /* Elementary string functions with memory allocation.  */
 
@@ -448,11 +466,14 @@ extern uint32_t *
 /* Return the length (number of units) of the first character in S.
    Return 0 if it is the NUL character.  Return -1 upon failure.  */
 extern int
-       u8_strmblen (const uint8_t *s);
+       u8_strmblen (const uint8_t *s)
+       _UC_ATTRIBUTE_PURE;
 extern int
-       u16_strmblen (const uint16_t *s);
+       u16_strmblen (const uint16_t *s)
+       _UC_ATTRIBUTE_PURE;
 extern int
-       u32_strmblen (const uint32_t *s);
+       u32_strmblen (const uint32_t *s)
+       _UC_ATTRIBUTE_PURE;
 
 /* Return the length (number of units) of the first character in S, putting
    its 'ucs4_t' representation in *PUC.  Return 0 if it is the NUL
@@ -487,20 +508,26 @@ extern const uint32_t *
 /* Return the number of units in S.  */
 /* Similar to strlen(), wcslen().  */
 extern size_t
-       u8_strlen (const uint8_t *s);
+       u8_strlen (const uint8_t *s)
+       _UC_ATTRIBUTE_PURE;
 extern size_t
-       u16_strlen (const uint16_t *s);
+       u16_strlen (const uint16_t *s)
+       _UC_ATTRIBUTE_PURE;
 extern size_t
-       u32_strlen (const uint32_t *s);
+       u32_strlen (const uint32_t *s)
+       _UC_ATTRIBUTE_PURE;
 
 /* Return the number of units in S, but at most MAXLEN.  */
 /* Similar to strnlen(), wcsnlen().  */
 extern size_t
-       u8_strnlen (const uint8_t *s, size_t maxlen);
+       u8_strnlen (const uint8_t *s, size_t maxlen)
+       _UC_ATTRIBUTE_PURE;
 extern size_t
-       u16_strnlen (const uint16_t *s, size_t maxlen);
+       u16_strnlen (const uint16_t *s, size_t maxlen)
+       _UC_ATTRIBUTE_PURE;
 extern size_t
-       u32_strnlen (const uint32_t *s, size_t maxlen);
+       u32_strnlen (const uint32_t *s, size_t maxlen)
+       _UC_ATTRIBUTE_PURE;
 
 /* Copy SRC to DEST.  */
 /* Similar to strcpy(), wcscpy().  */
@@ -562,16 +589,20 @@ extern uint32_t *
 #ifdef __sun
 /* Avoid a collision with the u8_strcmp() function in Solaris 11 libc.  */
 extern int
-       u8_strcmp_gnu (const uint8_t *s1, const uint8_t *s2);
+       u8_strcmp_gnu (const uint8_t *s1, const uint8_t *s2)
+       _UC_ATTRIBUTE_PURE;
 # define u8_strcmp u8_strcmp_gnu
 #else
 extern int
-       u8_strcmp (const uint8_t *s1, const uint8_t *s2);
+       u8_strcmp (const uint8_t *s1, const uint8_t *s2)
+       _UC_ATTRIBUTE_PURE;
 #endif
 extern int
-       u16_strcmp (const uint16_t *s1, const uint16_t *s2);
+       u16_strcmp (const uint16_t *s1, const uint16_t *s2)
+       _UC_ATTRIBUTE_PURE;
 extern int
-       u32_strcmp (const uint32_t *s1, const uint32_t *s2);
+       u32_strcmp (const uint32_t *s1, const uint32_t *s2)
+       _UC_ATTRIBUTE_PURE;
 
 /* Compare S1 and S2 using the collation rules of the current locale.
    Return -1 if S1 < S2, 0 if S1 = S2, 1 if S1 > S2.
@@ -587,11 +618,14 @@ extern int
 /* Compare no more than N units of S1 and S2.  */
 /* Similar to strncmp(), wcsncmp().  */
 extern int
-       u8_strncmp (const uint8_t *s1, const uint8_t *s2, size_t n);
+       u8_strncmp (const uint8_t *s1, const uint8_t *s2, size_t n)
+       _UC_ATTRIBUTE_PURE;
 extern int
-       u16_strncmp (const uint16_t *s1, const uint16_t *s2, size_t n);
+       u16_strncmp (const uint16_t *s1, const uint16_t *s2, size_t n)
+       _UC_ATTRIBUTE_PURE;
 extern int
-       u32_strncmp (const uint32_t *s1, const uint32_t *s2, size_t n);
+       u32_strncmp (const uint32_t *s1, const uint32_t *s2, size_t n)
+       _UC_ATTRIBUTE_PURE;
 
 /* Duplicate S, returning an identical malloc'd string.  */
 /* Similar to strdup(), wcsdup().  */
@@ -605,74 +639,98 @@ extern uint32_t *
 /* Find the first occurrence of UC in STR.  */
 /* Similar to strchr(), wcschr().  */
 extern uint8_t *
-       u8_strchr (const uint8_t *str, ucs4_t uc);
+       u8_strchr (const uint8_t *str, ucs4_t uc)
+       _UC_ATTRIBUTE_PURE;
 extern uint16_t *
-       u16_strchr (const uint16_t *str, ucs4_t uc);
+       u16_strchr (const uint16_t *str, ucs4_t uc)
+       _UC_ATTRIBUTE_PURE;
 extern uint32_t *
-       u32_strchr (const uint32_t *str, ucs4_t uc);
+       u32_strchr (const uint32_t *str, ucs4_t uc)
+       _UC_ATTRIBUTE_PURE;
 
 /* Find the last occurrence of UC in STR.  */
 /* Similar to strrchr(), wcsrchr().  */
 extern uint8_t *
-       u8_strrchr (const uint8_t *str, ucs4_t uc);
+       u8_strrchr (const uint8_t *str, ucs4_t uc)
+       _UC_ATTRIBUTE_PURE;
 extern uint16_t *
-       u16_strrchr (const uint16_t *str, ucs4_t uc);
+       u16_strrchr (const uint16_t *str, ucs4_t uc)
+       _UC_ATTRIBUTE_PURE;
 extern uint32_t *
-       u32_strrchr (const uint32_t *str, ucs4_t uc);
+       u32_strrchr (const uint32_t *str, ucs4_t uc)
+       _UC_ATTRIBUTE_PURE;
 
 /* Return the length of the initial segment of STR which consists entirely
    of Unicode characters not in REJECT.  */
 /* Similar to strcspn(), wcscspn().  */
 extern size_t
-       u8_strcspn (const uint8_t *str, const uint8_t *reject);
+       u8_strcspn (const uint8_t *str, const uint8_t *reject)
+       _UC_ATTRIBUTE_PURE;
 extern size_t
-       u16_strcspn (const uint16_t *str, const uint16_t *reject);
+       u16_strcspn (const uint16_t *str, const uint16_t *reject)
+       _UC_ATTRIBUTE_PURE;
 extern size_t
-       u32_strcspn (const uint32_t *str, const uint32_t *reject);
+       u32_strcspn (const uint32_t *str, const uint32_t *reject)
+       _UC_ATTRIBUTE_PURE;
 
 /* Return the length of the initial segment of STR which consists entirely
    of Unicode characters in ACCEPT.  */
 /* Similar to strspn(), wcsspn().  */
 extern size_t
-       u8_strspn (const uint8_t *str, const uint8_t *accept);
+       u8_strspn (const uint8_t *str, const uint8_t *accept)
+       _UC_ATTRIBUTE_PURE;
 extern size_t
-       u16_strspn (const uint16_t *str, const uint16_t *accept);
+       u16_strspn (const uint16_t *str, const uint16_t *accept)
+       _UC_ATTRIBUTE_PURE;
 extern size_t
-       u32_strspn (const uint32_t *str, const uint32_t *accept);
+       u32_strspn (const uint32_t *str, const uint32_t *accept)
+       _UC_ATTRIBUTE_PURE;
 
 /* Find the first occurrence in STR of any character in ACCEPT.  */
 /* Similar to strpbrk(), wcspbrk().  */
 extern uint8_t *
-       u8_strpbrk (const uint8_t *str, const uint8_t *accept);
+       u8_strpbrk (const uint8_t *str, const uint8_t *accept)
+       _UC_ATTRIBUTE_PURE;
 extern uint16_t *
-       u16_strpbrk (const uint16_t *str, const uint16_t *accept);
+       u16_strpbrk (const uint16_t *str, const uint16_t *accept)
+       _UC_ATTRIBUTE_PURE;
 extern uint32_t *
-       u32_strpbrk (const uint32_t *str, const uint32_t *accept);
+       u32_strpbrk (const uint32_t *str, const uint32_t *accept)
+       _UC_ATTRIBUTE_PURE;
 
 /* Find the first occurrence of NEEDLE in HAYSTACK.  */
 /* Similar to strstr(), wcsstr().  */
 extern uint8_t *
-       u8_strstr (const uint8_t *haystack, const uint8_t *needle);
+       u8_strstr (const uint8_t *haystack, const uint8_t *needle)
+       _UC_ATTRIBUTE_PURE;
 extern uint16_t *
-       u16_strstr (const uint16_t *haystack, const uint16_t *needle);
+       u16_strstr (const uint16_t *haystack, const uint16_t *needle)
+       _UC_ATTRIBUTE_PURE;
 extern uint32_t *
-       u32_strstr (const uint32_t *haystack, const uint32_t *needle);
+       u32_strstr (const uint32_t *haystack, const uint32_t *needle)
+       _UC_ATTRIBUTE_PURE;
 
 /* Test whether STR starts with PREFIX.  */
 extern bool
-       u8_startswith (const uint8_t *str, const uint8_t *prefix);
+       u8_startswith (const uint8_t *str, const uint8_t *prefix)
+       _UC_ATTRIBUTE_PURE;
 extern bool
-       u16_startswith (const uint16_t *str, const uint16_t *prefix);
+       u16_startswith (const uint16_t *str, const uint16_t *prefix)
+       _UC_ATTRIBUTE_PURE;
 extern bool
-       u32_startswith (const uint32_t *str, const uint32_t *prefix);
+       u32_startswith (const uint32_t *str, const uint32_t *prefix)
+       _UC_ATTRIBUTE_PURE;
 
 /* Test whether STR ends with SUFFIX.  */
 extern bool
-       u8_endswith (const uint8_t *str, const uint8_t *suffix);
+       u8_endswith (const uint8_t *str, const uint8_t *suffix)
+       _UC_ATTRIBUTE_PURE;
 extern bool
-       u16_endswith (const uint16_t *str, const uint16_t *suffix);
+       u16_endswith (const uint16_t *str, const uint16_t *suffix)
+       _UC_ATTRIBUTE_PURE;
 extern bool
-       u32_endswith (const uint32_t *str, const uint32_t *suffix);
+       u32_endswith (const uint32_t *str, const uint32_t *suffix)
+       _UC_ATTRIBUTE_PURE;
 
 /* Divide STR into tokens separated by characters in DELIM.
    This interface is actually more similar to wcstok than to strtok.  */
diff --git a/gl/unitypes.in.h b/gl/unitypes.in.h
index b1235e6..e642b7a 100644
--- a/gl/unitypes.in.h
+++ b/gl/unitypes.in.h
@@ -1,4 +1,4 @@
-/* Elementary types for the GNU UniString library.
+/* Elementary types and macros for the GNU UniString library.
    Copyright (C) 2002, 2005-2006, 2009-2012 Free Software Foundation, Inc.
 
    This program is free software: you can redistribute it and/or modify it
@@ -23,4 +23,24 @@
 /* Type representing a Unicode character.  */
 typedef uint32_t ucs4_t;
 
+/* Attribute of a function whose result depends only on the arguments
+   (not pointers!) and which has no side effects.  */
+#ifndef _UC_ATTRIBUTE_CONST
+# if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 95)
+#  define _UC_ATTRIBUTE_CONST __attribute__ ((__const__))
+# else
+#  define _UC_ATTRIBUTE_CONST
+# endif
+#endif
+
+/* Attribute of a function whose result depends only on the arguments
+   (possibly pointers) and global memory, and which has no side effects.  */
+#ifndef _UC_ATTRIBUTE_PURE
+# if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 96)
+#  define _UC_ATTRIBUTE_PURE __attribute__ ((__pure__))
+# else
+#  define _UC_ATTRIBUTE_PURE
+# endif
+#endif
+
 #endif /* _UNITYPES_H */
diff --git a/gl/wchar.in.h b/gl/wchar.in.h
index 4e92a77..f9bc30c 100644
--- a/gl/wchar.in.h
+++ b/gl/wchar.in.h
@@ -83,6 +83,14 @@
 #ifndef address@hidden@_WCHAR_H
 #define address@hidden@_WCHAR_H
 
+/* The __attribute__ feature is available in gcc versions 2.5 and later.
+   The attribute __pure__ was added in gcc 2.96.  */
+#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 96)
+# define _GL_ATTRIBUTE_PURE __attribute__ ((__pure__))
+#else
+# define _GL_ATTRIBUTE_PURE /* empty */
+#endif
+
 /* The definitions of _GL_FUNCDECL_RPL etc. are copied here.  */
 
 /* The definition of _GL_ARG_NONNULL is copied here.  */
@@ -135,11 +143,11 @@ typedef int rpl_mbstate_t;
 #   undef btowc
 #   define btowc rpl_btowc
 #  endif
-_GL_FUNCDECL_RPL (btowc, wint_t, (int c));
+_GL_FUNCDECL_RPL (btowc, wint_t, (int c) _GL_ATTRIBUTE_PURE);
 _GL_CXXALIAS_RPL (btowc, wint_t, (int c));
 # else
 #  if address@hidden@
-_GL_FUNCDECL_SYS (btowc, wint_t, (int c));
+_GL_FUNCDECL_SYS (btowc, wint_t, (int c) _GL_ATTRIBUTE_PURE);
 #  endif
 _GL_CXXALIAS_SYS (btowc, wint_t, (int c));
 # endif
@@ -160,12 +168,12 @@ _GL_WARN_ON_USE (btowc, "btowc is unportable - "
 #   undef wctob
 #   define wctob rpl_wctob
 #  endif
-_GL_FUNCDECL_RPL (wctob, int, (wint_t wc));
+_GL_FUNCDECL_RPL (wctob, int, (wint_t wc) _GL_ATTRIBUTE_PURE);
 _GL_CXXALIAS_RPL (wctob, int, (wint_t wc));
 # else
 #  if !defined wctob && address@hidden@
 /* wctob is provided by gnulib, or wctob exists but is not declared.  */
-_GL_FUNCDECL_SYS (wctob, int, (wint_t wc));
+_GL_FUNCDECL_SYS (wctob, int, (wint_t wc) _GL_ATTRIBUTE_PURE);
 #  endif
 _GL_CXXALIAS_SYS (wctob, int, (wint_t wc));
 # endif
@@ -426,12 +434,12 @@ _GL_WARN_ON_USE (wcsnrtombs, "wcsnrtombs is unportable - "
 #   undef wcwidth
 #   define wcwidth rpl_wcwidth
 #  endif
-_GL_FUNCDECL_RPL (wcwidth, int, (wchar_t));
+_GL_FUNCDECL_RPL (wcwidth, int, (wchar_t) _GL_ATTRIBUTE_PURE);
 _GL_CXXALIAS_RPL (wcwidth, int, (wchar_t));
 # else
 #  if address@hidden@
 /* wcwidth exists but is not declared.  */
-_GL_FUNCDECL_SYS (wcwidth, int, (wchar_t));
+_GL_FUNCDECL_SYS (wcwidth, int, (wchar_t) _GL_ATTRIBUTE_PURE);
 #  endif
 _GL_CXXALIAS_SYS (wcwidth, int, (wchar_t));
 # endif
@@ -448,7 +456,8 @@ _GL_WARN_ON_USE (wcwidth, "wcwidth is unportable - "
 /* Search N wide characters of S for C.  */
 #if @GNULIB_WMEMCHR@
 # if address@hidden@
-_GL_FUNCDECL_SYS (wmemchr, wchar_t *, (const wchar_t *s, wchar_t c, size_t n));
+_GL_FUNCDECL_SYS (wmemchr, wchar_t *, (const wchar_t *s, wchar_t c, size_t n)
+                                      _GL_ATTRIBUTE_PURE);
 # endif
   /* On some systems, this function is defined as an overloaded function:
        extern "C++" {
@@ -479,7 +488,8 @@ _GL_WARN_ON_USE (wmemchr, "wmemchr is unportable - "
 #if @GNULIB_WMEMCMP@
 # if address@hidden@
 _GL_FUNCDECL_SYS (wmemcmp, int,
-                  (const wchar_t *s1, const wchar_t *s2, size_t n));
+                  (const wchar_t *s1, const wchar_t *s2, size_t n)
+                  _GL_ATTRIBUTE_PURE);
 # endif
 _GL_CXXALIAS_SYS (wmemcmp, int,
                   (const wchar_t *s1, const wchar_t *s2, size_t n));
@@ -549,7 +559,7 @@ _GL_WARN_ON_USE (wmemset, "wmemset is unportable - "
 /* Return the number of wide characters in S.  */
 #if @GNULIB_WCSLEN@
 # if address@hidden@
-_GL_FUNCDECL_SYS (wcslen, size_t, (const wchar_t *s));
+_GL_FUNCDECL_SYS (wcslen, size_t, (const wchar_t *s) _GL_ATTRIBUTE_PURE);
 # endif
 _GL_CXXALIAS_SYS (wcslen, size_t, (const wchar_t *s));
 _GL_CXXALIASWARN (wcslen);
@@ -565,7 +575,8 @@ _GL_WARN_ON_USE (wcslen, "wcslen is unportable - "
 /* Return the number of wide characters in S, but at most MAXLEN.  */
 #if @GNULIB_WCSNLEN@
 # if address@hidden@
-_GL_FUNCDECL_SYS (wcsnlen, size_t, (const wchar_t *s, size_t maxlen));
+_GL_FUNCDECL_SYS (wcsnlen, size_t, (const wchar_t *s, size_t maxlen)
+                                   _GL_ATTRIBUTE_PURE);
 # endif
 _GL_CXXALIAS_SYS (wcsnlen, size_t, (const wchar_t *s, size_t maxlen));
 _GL_CXXALIASWARN (wcsnlen);
@@ -684,7 +695,8 @@ _GL_WARN_ON_USE (wcsncat, "wcsncat is unportable - "
 /* Compare S1 and S2.  */
 #if @GNULIB_WCSCMP@
 # if address@hidden@
-_GL_FUNCDECL_SYS (wcscmp, int, (const wchar_t *s1, const wchar_t *s2));
+_GL_FUNCDECL_SYS (wcscmp, int, (const wchar_t *s1, const wchar_t *s2)
+                               _GL_ATTRIBUTE_PURE);
 # endif
 _GL_CXXALIAS_SYS (wcscmp, int, (const wchar_t *s1, const wchar_t *s2));
 _GL_CXXALIASWARN (wcscmp);
@@ -701,7 +713,8 @@ _GL_WARN_ON_USE (wcscmp, "wcscmp is unportable - "
 #if @GNULIB_WCSNCMP@
 # if address@hidden@
 _GL_FUNCDECL_SYS (wcsncmp, int,
-                  (const wchar_t *s1, const wchar_t *s2, size_t n));
+                  (const wchar_t *s1, const wchar_t *s2, size_t n)
+                  _GL_ATTRIBUTE_PURE);
 # endif
 _GL_CXXALIAS_SYS (wcsncmp, int,
                   (const wchar_t *s1, const wchar_t *s2, size_t n));
@@ -718,7 +731,8 @@ _GL_WARN_ON_USE (wcsncmp, "wcsncmp is unportable - "
 /* Compare S1 and S2, ignoring case.  */
 #if @GNULIB_WCSCASECMP@
 # if address@hidden@
-_GL_FUNCDECL_SYS (wcscasecmp, int, (const wchar_t *s1, const wchar_t *s2));
+_GL_FUNCDECL_SYS (wcscasecmp, int, (const wchar_t *s1, const wchar_t *s2)
+                                   _GL_ATTRIBUTE_PURE);
 # endif
 _GL_CXXALIAS_SYS (wcscasecmp, int, (const wchar_t *s1, const wchar_t *s2));
 _GL_CXXALIASWARN (wcscasecmp);
@@ -735,7 +749,8 @@ _GL_WARN_ON_USE (wcscasecmp, "wcscasecmp is unportable - "
 #if @GNULIB_WCSNCASECMP@
 # if address@hidden@
 _GL_FUNCDECL_SYS (wcsncasecmp, int,
-                  (const wchar_t *s1, const wchar_t *s2, size_t n));
+                  (const wchar_t *s1, const wchar_t *s2, size_t n)
+                  _GL_ATTRIBUTE_PURE);
 # endif
 _GL_CXXALIAS_SYS (wcsncasecmp, int,
                   (const wchar_t *s1, const wchar_t *s2, size_t n));
@@ -803,7 +818,8 @@ _GL_WARN_ON_USE (wcsdup, "wcsdup is unportable - "
 /* Find the first occurrence of WC in WCS.  */
 #if @GNULIB_WCSCHR@
 # if address@hidden@
-_GL_FUNCDECL_SYS (wcschr, wchar_t *, (const wchar_t *wcs, wchar_t wc));
+_GL_FUNCDECL_SYS (wcschr, wchar_t *, (const wchar_t *wcs, wchar_t wc)
+                                     _GL_ATTRIBUTE_PURE);
 # endif
   /* On some systems, this function is defined as an overloaded function:
        extern "C++" {
@@ -832,7 +848,8 @@ _GL_WARN_ON_USE (wcschr, "wcschr is unportable - "
 /* Find the last occurrence of WC in WCS.  */
 #if @GNULIB_WCSRCHR@
 # if address@hidden@
-_GL_FUNCDECL_SYS (wcsrchr, wchar_t *, (const wchar_t *wcs, wchar_t wc));
+_GL_FUNCDECL_SYS (wcsrchr, wchar_t *, (const wchar_t *wcs, wchar_t wc)
+                                      _GL_ATTRIBUTE_PURE);
 # endif
   /* On some systems, this function is defined as an overloaded function:
        extern "C++" {
@@ -862,7 +879,8 @@ _GL_WARN_ON_USE (wcsrchr, "wcsrchr is unportable - "
    of wide characters not in REJECT.  */
 #if @GNULIB_WCSCSPN@
 # if address@hidden@
-_GL_FUNCDECL_SYS (wcscspn, size_t, (const wchar_t *wcs, const wchar_t 
*reject));
+_GL_FUNCDECL_SYS (wcscspn, size_t, (const wchar_t *wcs, const wchar_t *reject)
+                                   _GL_ATTRIBUTE_PURE);
 # endif
 _GL_CXXALIAS_SYS (wcscspn, size_t, (const wchar_t *wcs, const wchar_t 
*reject));
 _GL_CXXALIASWARN (wcscspn);
@@ -879,7 +897,8 @@ _GL_WARN_ON_USE (wcscspn, "wcscspn is unportable - "
    of wide characters in ACCEPT.  */
 #if @GNULIB_WCSSPN@
 # if address@hidden@
-_GL_FUNCDECL_SYS (wcsspn, size_t, (const wchar_t *wcs, const wchar_t *accept));
+_GL_FUNCDECL_SYS (wcsspn, size_t, (const wchar_t *wcs, const wchar_t *accept)
+                                  _GL_ATTRIBUTE_PURE);
 # endif
 _GL_CXXALIAS_SYS (wcsspn, size_t, (const wchar_t *wcs, const wchar_t *accept));
 _GL_CXXALIASWARN (wcsspn);
@@ -896,7 +915,8 @@ _GL_WARN_ON_USE (wcsspn, "wcsspn is unportable - "
 #if @GNULIB_WCSPBRK@
 # if address@hidden@
 _GL_FUNCDECL_SYS (wcspbrk, wchar_t *,
-                  (const wchar_t *wcs, const wchar_t *accept));
+                  (const wchar_t *wcs, const wchar_t *accept)
+                  _GL_ATTRIBUTE_PURE);
 # endif
   /* On some systems, this function is defined as an overloaded function:
        extern "C++" {
@@ -928,7 +948,8 @@ _GL_WARN_ON_USE (wcspbrk, "wcspbrk is unportable - "
 #if @GNULIB_WCSSTR@
 # if address@hidden@
 _GL_FUNCDECL_SYS (wcsstr, wchar_t *,
-                  (const wchar_t *haystack, const wchar_t *needle));
+                  (const wchar_t *haystack, const wchar_t *needle)
+                  _GL_ATTRIBUTE_PURE);
 # endif
   /* On some systems, this function is defined as an overloaded function:
        extern "C++" {
@@ -982,11 +1003,13 @@ _GL_WARN_ON_USE (wcstok, "wcstok is unportable - "
 #   undef wcswidth
 #   define wcswidth rpl_wcswidth
 #  endif
-_GL_FUNCDECL_RPL (wcswidth, int, (const wchar_t *s, size_t n));
+_GL_FUNCDECL_RPL (wcswidth, int, (const wchar_t *s, size_t n)
+                                 _GL_ATTRIBUTE_PURE);
 _GL_CXXALIAS_RPL (wcswidth, int, (const wchar_t *s, size_t n));
 # else
 #  if address@hidden@
-_GL_FUNCDECL_SYS (wcswidth, int, (const wchar_t *s, size_t n));
+_GL_FUNCDECL_SYS (wcswidth, int, (const wchar_t *s, size_t n)
+                                 _GL_ATTRIBUTE_PURE);
 #  endif
 _GL_CXXALIAS_SYS (wcswidth, int, (const wchar_t *s, size_t n));
 # endif
diff --git a/gltests/Makefile.am b/gltests/Makefile.am
index 68a1d67..e3b2847 100644
--- a/gltests/Makefile.am
+++ b/gltests/Makefile.am
@@ -620,12 +620,15 @@ locale.h: locale.in.h $(top_builddir)/config.status 
$(CXXDEFS_H) $(ARG_NONNULL_H
              -e 's|@''PRAGMA_SYSTEM_HEADER''@|@PRAGMA_SYSTEM_HEADER@|g' \
              -e 's|@''PRAGMA_COLUMNS''@|@PRAGMA_COLUMNS@|g' \
              -e 's|@''NEXT_LOCALE_H''@|$(NEXT_LOCALE_H)|g' \
+             -e 's/@''GNULIB_LOCALECONV''@/$(GNULIB_LOCALECONV)/g' \
              -e 's/@''GNULIB_SETLOCALE''@/$(GNULIB_SETLOCALE)/g' \
              -e 's/@''GNULIB_DUPLOCALE''@/$(GNULIB_DUPLOCALE)/g' \
              -e 's|@''HAVE_DUPLOCALE''@|$(HAVE_DUPLOCALE)|g' \
              -e 's|@''HAVE_XLOCALE_H''@|$(HAVE_XLOCALE_H)|g' \
+             -e 's|@''REPLACE_LOCALECONV''@|$(REPLACE_LOCALECONV)|g' \
              -e 's|@''REPLACE_SETLOCALE''@|$(REPLACE_SETLOCALE)|g' \
              -e 's|@''REPLACE_DUPLOCALE''@|$(REPLACE_DUPLOCALE)|g' \
+             -e 's|@''REPLACE_STRUCT_LCONV''@|$(REPLACE_STRUCT_LCONV)|g' \
              -e '/definitions of _GL_FUNCDECL_RPL/r $(CXXDEFS_H)' \
              -e '/definition of _GL_ARG_NONNULL/r $(ARG_NONNULL_H)' \
              -e '/definition of _GL_WARN_ON_USE/r $(WARN_ON_USE_H)' \
diff --git a/gltests/fpucw.h b/gltests/fpucw.h
index a62c51d..23e4c81 100644
--- a/gltests/fpucw.h
+++ b/gltests/fpucw.h
@@ -30,7 +30,8 @@
 
    On some platforms, such as NetBSD, the default precision is set to
    "double precision".  This means that 'long double' instructions will operate
-   only as 'double', i.e. lead wrong results.
+   only as 'double', i.e. lead to wrong results.  Similarly on FreeBSD 6.4, at
+   least for the division of 'long double' numbers.
 
    The FPU control word is under control of the application, i.e. it is
    not required to be set either way by the ABI.  (In fact, the i386 ABI
diff --git a/gltests/locale.in.h b/gltests/locale.in.h
index a97e3e7..7747902 100644
--- a/gltests/locale.in.h
+++ b/gltests/locale.in.h
@@ -47,6 +47,111 @@
 # define LC_MESSAGES 1729
 #endif
 
+/* Bionic libc's 'struct lconv' is just a dummy.  */
+#if @REPLACE_STRUCT_LCONV@
+# define lconv rpl_lconv
+struct lconv
+{
+  /* All 'char *' are actually 'const char *'.  */
+
+  /* Members that depend on the LC_NUMERIC category of the locale.  See
+     
<http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap07.html#tag_07_03_04>
 */
+
+  /* Symbol used as decimal point.  */
+  char *decimal_point;
+  /* Symbol used to separate groups of digits to the left of the decimal
+     point.  */
+  char *thousands_sep;
+  /* Definition of the size of groups of digits to the left of the decimal
+     point.  */
+  char *grouping;
+
+  /* Members that depend on the LC_MONETARY category of the locale.  See
+     
<http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap07.html#tag_07_03_03>
 */
+
+  /* Symbol used as decimal point.  */
+  char *mon_decimal_point;
+  /* Symbol used to separate groups of digits to the left of the decimal
+     point.  */
+  char *mon_thousands_sep;
+  /* Definition of the size of groups of digits to the left of the decimal
+     point.  */
+  char *mon_grouping;
+  /* Sign used to indicate a value >= 0.  */
+  char *positive_sign;
+  /* Sign used to indicate a value < 0.  */
+  char *negative_sign;
+
+  /* For formatting local currency.  */
+  /* Currency symbol (3 characters) followed by separator (1 character).  */
+  char *currency_symbol;
+  /* Number of digits after the decimal point.  */
+  char frac_digits;
+  /* For values >= 0: 1 if the currency symbol precedes the number, 0 if it
+     comes after the number.  */
+  char p_cs_precedes;
+  /* For values >= 0: Position of the sign.  */
+  char p_sign_posn;
+  /* For values >= 0: Placement of spaces between currency symbol, sign, and
+     number.  */
+  char p_sep_by_space;
+  /* For values < 0: 1 if the currency symbol precedes the number, 0 if it
+     comes after the number.  */
+  char n_cs_precedes;
+  /* For values < 0: Position of the sign.  */
+  char n_sign_posn;
+  /* For values < 0: Placement of spaces between currency symbol, sign, and
+     number.  */
+  char n_sep_by_space;
+
+  /* For formatting international currency.  */
+  /* Currency symbol (3 characters) followed by separator (1 character).  */
+  char *int_curr_symbol;
+  /* Number of digits after the decimal point.  */
+  char int_frac_digits;
+  /* For values >= 0: 1 if the currency symbol precedes the number, 0 if it
+     comes after the number.  */
+  char int_p_cs_precedes;
+  /* For values >= 0: Position of the sign.  */
+  char int_p_sign_posn;
+  /* For values >= 0: Placement of spaces between currency symbol, sign, and
+     number.  */
+  char int_p_sep_by_space;
+  /* For values < 0: 1 if the currency symbol precedes the number, 0 if it
+     comes after the number.  */
+  char int_n_cs_precedes;
+  /* For values < 0: Position of the sign.  */
+  char int_n_sign_posn;
+  /* For values < 0: Placement of spaces between currency symbol, sign, and
+     number.  */
+  char int_n_sep_by_space;
+};
+#endif
+
+#if @GNULIB_LOCALECONV@
+# if @REPLACE_LOCALECONV@
+#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)
+#   undef localeconv
+#   define localeconv rpl_localeconv
+#  endif
+_GL_FUNCDECL_RPL (localeconv, struct lconv *, (void));
+_GL_CXXALIAS_RPL (localeconv, struct lconv *, (void));
+# else
+_GL_CXXALIAS_SYS (localeconv, struct lconv *, (void));
+# endif
+_GL_CXXALIASWARN (localeconv);
+#elif @REPLACE_STRUCT_LCONV@
+# undef localeconv
+# define localeconv localeconv_used_without_requesting_gnulib_module_localeconv
+#elif defined GNULIB_POSIXCHECK
+# undef localeconv
+# if HAVE_RAW_DECL_LOCALECONV
+_GL_WARN_ON_USE (localeconv,
+                 "localeconv returns too few information on some platforms - "
+                 "use gnulib module localeconv for portability");
+# endif
+#endif
+
 #if @GNULIB_SETLOCALE@
 # if @REPLACE_SETLOCALE@
 #  if !(defined __cplusplus && defined GNULIB_NAMESPACE)
diff --git a/gltests/macros.h b/gltests/macros.h
index 77a92f8..478004c 100644
--- a/gltests/macros.h
+++ b/gltests/macros.h
@@ -66,3 +66,8 @@
 /* STREQ (str1, str2)
    Return true if two strings compare equal.  */
 #define STREQ(a, b) (strcmp (a, b) == 0)
+
+/* Some numbers in the interval [0,1).  */
+extern const float randomf[1000];
+extern const double randomd[1000];
+extern const long double randoml[1000];
diff --git a/gltests/test-locale.c b/gltests/test-locale.c
index 1cd3dac..e884ea1 100644
--- a/gltests/test-locale.c
+++ b/gltests/test-locale.c
@@ -38,6 +38,10 @@ int a[] =
 locale_t b = LC_GLOBAL_LOCALE;
 #endif
 
+/* Check that the 'struct lconv' type is defined.  */
+struct lconv l;
+int ls;
+
 /* Check that NULL can be passed through varargs as a pointer type,
    per POSIX 2008.  */
 verify (sizeof NULL == sizeof (void *));
@@ -45,5 +49,31 @@ verify (sizeof NULL == sizeof (void *));
 int
 main ()
 {
+  /* Check that 'struct lconv' has the ISO C and POSIX specified members.  */
+  ls += sizeof (*l.decimal_point);
+  ls += sizeof (*l.thousands_sep);
+  ls += sizeof (*l.grouping);
+  ls += sizeof (*l.mon_decimal_point);
+  ls += sizeof (*l.mon_thousands_sep);
+  ls += sizeof (*l.mon_grouping);
+  ls += sizeof (*l.positive_sign);
+  ls += sizeof (*l.negative_sign);
+  ls += sizeof (*l.currency_symbol);
+  ls += sizeof (l.frac_digits);
+  ls += sizeof (l.p_cs_precedes);
+  ls += sizeof (l.p_sign_posn);
+  ls += sizeof (l.p_sep_by_space);
+  ls += sizeof (l.n_cs_precedes);
+  ls += sizeof (l.n_sign_posn);
+  ls += sizeof (l.n_sep_by_space);
+  ls += sizeof (*l.int_curr_symbol);
+  ls += sizeof (l.int_frac_digits);
+  ls += sizeof (l.int_p_cs_precedes);
+  ls += sizeof (l.int_p_sign_posn);
+  ls += sizeof (l.int_p_sep_by_space);
+  ls += sizeof (l.int_n_cs_precedes);
+  ls += sizeof (l.int_n_sign_posn);
+  ls += sizeof (l.int_n_sep_by_space);
+
   return 0;
 }
diff --git a/lib/build-aux/gnupload b/lib/build-aux/gnupload
index eb450a0..40a59d3 100755
--- a/lib/build-aux/gnupload
+++ b/lib/build-aux/gnupload
@@ -3,7 +3,7 @@
 
 scriptversion=2012-01-15.15; # UTC
 
-# Copyright (C) 2004-2010, 2012 Free Software Foundation, Inc.
+# Copyright (C) 2004-2012 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
diff --git a/lib/gl/m4/math_h.m4 b/lib/gl/m4/math_h.m4
index a5a71f2..ff1654e 100644
--- a/lib/gl/m4/math_h.m4
+++ b/lib/gl/m4/math_h.m4
@@ -1,4 +1,4 @@
-# math_h.m4 serial 79
+# math_h.m4 serial 104
 dnl Copyright (C) 2007-2012 Free Software Foundation, Inc.
 dnl This file is free software; the Free Software Foundation
 dnl gives unlimited permission to copy and/or distribute it,
@@ -41,9 +41,12 @@ AC_DEFUN([gl_MATH_H],
   gl_WARN_ON_USE_PREPARE([[#include <math.h>]],
     [acosf acosl asinf asinl atanf atanl
      cbrt cbrtf cbrtl ceilf ceill copysign copysignf copysignl cosf cosl coshf
-     expf expl fabsf fabsl floorf floorl fma fmaf fmal
+     expf expl exp2 exp2f exp2l expm1 expm1f expm1l
+     fabsf fabsl floorf floorl fma fmaf fmal
      fmod fmodf fmodl frexpf frexpl hypotf hypotl
-     ldexpf ldexpl logb logf logl log10f log10l modf modff modfl powf
+     ldexpf ldexpl
+     logb log logf logl log10f log10l log1p log1pf log1pl log2 log2f log2l
+     modf modff modfl powf
      remainder remainderf remainderl
      rint rintf rintl round roundf roundl sinf sinl sinhf sqrtf sqrtl
      tanf tanl tanhf trunc truncf truncl])
@@ -81,6 +84,12 @@ AC_DEFUN([gl_MATH_H_DEFAULTS],
   GNULIB_COSHF=0;      AC_SUBST([GNULIB_COSHF])
   GNULIB_EXPF=0;       AC_SUBST([GNULIB_EXPF])
   GNULIB_EXPL=0;       AC_SUBST([GNULIB_EXPL])
+  GNULIB_EXP2=0;       AC_SUBST([GNULIB_EXP2])
+  GNULIB_EXP2F=0;      AC_SUBST([GNULIB_EXP2F])
+  GNULIB_EXP2L=0;      AC_SUBST([GNULIB_EXP2L])
+  GNULIB_EXPM1=0;      AC_SUBST([GNULIB_EXPM1])
+  GNULIB_EXPM1F=0;     AC_SUBST([GNULIB_EXPM1F])
+  GNULIB_EXPM1L=0;     AC_SUBST([GNULIB_EXPM1L])
   GNULIB_FABSF=0;      AC_SUBST([GNULIB_FABSF])
   GNULIB_FABSL=0;      AC_SUBST([GNULIB_FABSL])
   GNULIB_FLOOR=0;      AC_SUBST([GNULIB_FLOOR])
@@ -107,10 +116,17 @@ AC_DEFUN([gl_MATH_H_DEFAULTS],
   GNULIB_LDEXPF=0;     AC_SUBST([GNULIB_LDEXPF])
   GNULIB_LDEXPL=0;     AC_SUBST([GNULIB_LDEXPL])
   GNULIB_LOGB=0;       AC_SUBST([GNULIB_LOGB])
+  GNULIB_LOG=0;        AC_SUBST([GNULIB_LOG])
   GNULIB_LOGF=0;       AC_SUBST([GNULIB_LOGF])
   GNULIB_LOGL=0;       AC_SUBST([GNULIB_LOGL])
   GNULIB_LOG10F=0;     AC_SUBST([GNULIB_LOG10F])
   GNULIB_LOG10L=0;     AC_SUBST([GNULIB_LOG10L])
+  GNULIB_LOG1P=0;      AC_SUBST([GNULIB_LOG1P])
+  GNULIB_LOG1PF=0;     AC_SUBST([GNULIB_LOG1PF])
+  GNULIB_LOG1PL=0;     AC_SUBST([GNULIB_LOG1PL])
+  GNULIB_LOG2=0;       AC_SUBST([GNULIB_LOG2])
+  GNULIB_LOG2F=0;      AC_SUBST([GNULIB_LOG2F])
+  GNULIB_LOG2L=0;      AC_SUBST([GNULIB_LOG2L])
   GNULIB_MODF=0;       AC_SUBST([GNULIB_MODF])
   GNULIB_MODFF=0;      AC_SUBST([GNULIB_MODFF])
   GNULIB_MODFL=0;      AC_SUBST([GNULIB_MODFL])
@@ -148,13 +164,14 @@ AC_DEFUN([gl_MATH_H_DEFAULTS],
   HAVE_CBRTF=1;                AC_SUBST([HAVE_CBRTF])
   HAVE_CBRTL=1;                AC_SUBST([HAVE_CBRTL])
   HAVE_COPYSIGN=1;             AC_SUBST([HAVE_COPYSIGN])
-  HAVE_COPYSIGNF=1;            AC_SUBST([HAVE_COPYSIGNF])
   HAVE_COPYSIGNL=1;            AC_SUBST([HAVE_COPYSIGNL])
   HAVE_COSF=1;                 AC_SUBST([HAVE_COSF])
   HAVE_COSL=1;                 AC_SUBST([HAVE_COSL])
   HAVE_COSHF=1;                AC_SUBST([HAVE_COSHF])
   HAVE_EXPF=1;                 AC_SUBST([HAVE_EXPF])
   HAVE_EXPL=1;                 AC_SUBST([HAVE_EXPL])
+  HAVE_EXPM1=1;                AC_SUBST([HAVE_EXPM1])
+  HAVE_EXPM1F=1;               AC_SUBST([HAVE_EXPM1F])
   HAVE_FABSF=1;                AC_SUBST([HAVE_FABSF])
   HAVE_FABSL=1;                AC_SUBST([HAVE_FABSL])
   HAVE_FMA=1;                  AC_SUBST([HAVE_FMA])
@@ -173,14 +190,15 @@ AC_DEFUN([gl_MATH_H_DEFAULTS],
   HAVE_LOGL=1;                 AC_SUBST([HAVE_LOGL])
   HAVE_LOG10F=1;               AC_SUBST([HAVE_LOG10F])
   HAVE_LOG10L=1;               AC_SUBST([HAVE_LOG10L])
+  HAVE_LOG1P=1;                AC_SUBST([HAVE_LOG1P])
+  HAVE_LOG1PF=1;               AC_SUBST([HAVE_LOG1PF])
+  HAVE_LOG1PL=1;               AC_SUBST([HAVE_LOG1PL])
   HAVE_MODFF=1;                AC_SUBST([HAVE_MODFF])
   HAVE_MODFL=1;                AC_SUBST([HAVE_MODFL])
   HAVE_POWF=1;                 AC_SUBST([HAVE_POWF])
   HAVE_REMAINDER=1;            AC_SUBST([HAVE_REMAINDER])
   HAVE_REMAINDERF=1;           AC_SUBST([HAVE_REMAINDERF])
-  HAVE_REMAINDERL=1;           AC_SUBST([HAVE_REMAINDERL])
   HAVE_RINT=1;                 AC_SUBST([HAVE_RINT])
-  HAVE_RINTF=1;                AC_SUBST([HAVE_RINTF])
   HAVE_RINTL=1;                AC_SUBST([HAVE_RINTL])
   HAVE_SINF=1;                 AC_SUBST([HAVE_SINF])
   HAVE_SINL=1;                 AC_SUBST([HAVE_SINL])
@@ -197,8 +215,13 @@ AC_DEFUN([gl_MATH_H_DEFAULTS],
   HAVE_DECL_CBRTL=1;           AC_SUBST([HAVE_DECL_CBRTL])
   HAVE_DECL_CEILF=1;           AC_SUBST([HAVE_DECL_CEILF])
   HAVE_DECL_CEILL=1;           AC_SUBST([HAVE_DECL_CEILL])
+  HAVE_DECL_COPYSIGNF=1;       AC_SUBST([HAVE_DECL_COPYSIGNF])
   HAVE_DECL_COSL=1;            AC_SUBST([HAVE_DECL_COSL])
   HAVE_DECL_EXPL=1;            AC_SUBST([HAVE_DECL_EXPL])
+  HAVE_DECL_EXP2=1;            AC_SUBST([HAVE_DECL_EXP2])
+  HAVE_DECL_EXP2F=1;           AC_SUBST([HAVE_DECL_EXP2F])
+  HAVE_DECL_EXP2L=1;           AC_SUBST([HAVE_DECL_EXP2L])
+  HAVE_DECL_EXPM1L=1;          AC_SUBST([HAVE_DECL_EXPM1L])
   HAVE_DECL_FLOORF=1;          AC_SUBST([HAVE_DECL_FLOORF])
   HAVE_DECL_FLOORL=1;          AC_SUBST([HAVE_DECL_FLOORL])
   HAVE_DECL_FREXPL=1;          AC_SUBST([HAVE_DECL_FREXPL])
@@ -206,7 +229,12 @@ AC_DEFUN([gl_MATH_H_DEFAULTS],
   HAVE_DECL_LOGB=1;            AC_SUBST([HAVE_DECL_LOGB])
   HAVE_DECL_LOGL=1;            AC_SUBST([HAVE_DECL_LOGL])
   HAVE_DECL_LOG10L=1;          AC_SUBST([HAVE_DECL_LOG10L])
+  HAVE_DECL_LOG2=1;            AC_SUBST([HAVE_DECL_LOG2])
+  HAVE_DECL_LOG2F=1;           AC_SUBST([HAVE_DECL_LOG2F])
+  HAVE_DECL_LOG2L=1;           AC_SUBST([HAVE_DECL_LOG2L])
   HAVE_DECL_REMAINDER=1;       AC_SUBST([HAVE_DECL_REMAINDER])
+  HAVE_DECL_REMAINDERL=1;      AC_SUBST([HAVE_DECL_REMAINDERL])
+  HAVE_DECL_RINTF=1;           AC_SUBST([HAVE_DECL_RINTF])
   HAVE_DECL_ROUND=1;           AC_SUBST([HAVE_DECL_ROUND])
   HAVE_DECL_ROUNDF=1;          AC_SUBST([HAVE_DECL_ROUNDF])
   HAVE_DECL_ROUNDL=1;          AC_SUBST([HAVE_DECL_ROUNDL])
@@ -221,6 +249,10 @@ AC_DEFUN([gl_MATH_H_DEFAULTS],
   REPLACE_CEIL=0;              AC_SUBST([REPLACE_CEIL])
   REPLACE_CEILF=0;             AC_SUBST([REPLACE_CEILF])
   REPLACE_CEILL=0;             AC_SUBST([REPLACE_CEILL])
+  REPLACE_EXPM1=0;             AC_SUBST([REPLACE_EXPM1])
+  REPLACE_EXPM1F=0;            AC_SUBST([REPLACE_EXPM1F])
+  REPLACE_EXP2=0;              AC_SUBST([REPLACE_EXP2])
+  REPLACE_EXP2L=0;             AC_SUBST([REPLACE_EXP2L])
   REPLACE_FABSL=0;             AC_SUBST([REPLACE_FABSL])
   REPLACE_FLOOR=0;             AC_SUBST([REPLACE_FLOOR])
   REPLACE_FLOORF=0;            AC_SUBST([REPLACE_FLOORF])
@@ -242,6 +274,15 @@ AC_DEFUN([gl_MATH_H_DEFAULTS],
   REPLACE_ISINF=0;             AC_SUBST([REPLACE_ISINF])
   REPLACE_ISNAN=0;             AC_SUBST([REPLACE_ISNAN])
   REPLACE_LDEXPL=0;            AC_SUBST([REPLACE_LDEXPL])
+  REPLACE_LOG=0;               AC_SUBST([REPLACE_LOG])
+  REPLACE_LOGF=0;              AC_SUBST([REPLACE_LOGF])
+  REPLACE_LOGL=0;              AC_SUBST([REPLACE_LOGL])
+  REPLACE_LOG1P=0;             AC_SUBST([REPLACE_LOG1P])
+  REPLACE_LOG1PF=0;            AC_SUBST([REPLACE_LOG1PF])
+  REPLACE_LOG1PL=0;            AC_SUBST([REPLACE_LOG1PL])
+  REPLACE_LOG2=0;              AC_SUBST([REPLACE_LOG2])
+  REPLACE_LOG2F=0;             AC_SUBST([REPLACE_LOG2F])
+  REPLACE_LOG2L=0;             AC_SUBST([REPLACE_LOG2L])
   REPLACE_MODF=0;              AC_SUBST([REPLACE_MODF])
   REPLACE_MODFF=0;             AC_SUBST([REPLACE_MODFF])
   REPLACE_MODFL=0;             AC_SUBST([REPLACE_MODFL])
@@ -254,6 +295,7 @@ AC_DEFUN([gl_MATH_H_DEFAULTS],
   REPLACE_ROUNDL=0;            AC_SUBST([REPLACE_ROUNDL])
   REPLACE_SIGNBIT=0;           AC_SUBST([REPLACE_SIGNBIT])
   REPLACE_SIGNBIT_USING_GCC=0; AC_SUBST([REPLACE_SIGNBIT_USING_GCC])
+  REPLACE_SQRTL=0;             AC_SUBST([REPLACE_SQRTL])
   REPLACE_TRUNC=0;             AC_SUBST([REPLACE_TRUNC])
   REPLACE_TRUNCF=0;            AC_SUBST([REPLACE_TRUNCF])
   REPLACE_TRUNCL=0;            AC_SUBST([REPLACE_TRUNCL])
diff --git a/lib/gl/stdlib.in.h b/lib/gl/stdlib.in.h
index 8de1e70..2214c92 100644
--- a/lib/gl/stdlib.in.h
+++ b/lib/gl/stdlib.in.h
@@ -94,6 +94,14 @@ struct random_data
 # include <unistd.h>
 #endif
 
+/* The __attribute__ feature is available in gcc versions 2.5 and later.
+   The attribute __pure__ was added in gcc 2.96.  */
+#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 96)
+# define _GL_ATTRIBUTE_PURE __attribute__ ((__pure__))
+#else
+# define _GL_ATTRIBUTE_PURE /* empty */
+#endif
+
 /* The definition of _Noreturn is copied here.  */
 
 /* The definitions of _GL_FUNCDECL_RPL etc. are copied here.  */
@@ -138,7 +146,9 @@ _GL_WARN_ON_USE (_Exit, "_Exit is unportable - "
 /* Parse a signed decimal integer.
    Returns the value of the integer.  Errors are not detected.  */
 # if address@hidden@
-_GL_FUNCDECL_SYS (atoll, long long, (const char *string) _GL_ARG_NONNULL 
((1)));
+_GL_FUNCDECL_SYS (atoll, long long, (const char *string)
+                                    _GL_ATTRIBUTE_PURE
+                                    _GL_ARG_NONNULL ((1)));
 # endif
 _GL_CXXALIAS_SYS (atoll, long long, (const char *string));
 _GL_CXXALIASWARN (atoll);
diff --git a/lib/gl/string.in.h b/lib/gl/string.in.h
index 26652d3..ed187c9 100644
--- a/lib/gl/string.in.h
+++ b/lib/gl/string.in.h
@@ -724,10 +724,14 @@ _GL_WARN_ON_USE (strtok_r, "strtok_r is unportable - "
 #  if !(defined __cplusplus && defined GNULIB_NAMESPACE)
 #   define mbslen rpl_mbslen
 #  endif
-_GL_FUNCDECL_RPL (mbslen, size_t, (const char *string) _GL_ARG_NONNULL ((1)));
+_GL_FUNCDECL_RPL (mbslen, size_t, (const char *string)
+                                  _GL_ATTRIBUTE_PURE
+                                  _GL_ARG_NONNULL ((1)));
 _GL_CXXALIAS_RPL (mbslen, size_t, (const char *string));
 # else
-_GL_FUNCDECL_SYS (mbslen, size_t, (const char *string) _GL_ARG_NONNULL ((1)));
+_GL_FUNCDECL_SYS (mbslen, size_t, (const char *string)
+                                  _GL_ATTRIBUTE_PURE
+                                  _GL_ARG_NONNULL ((1)));
 _GL_CXXALIAS_SYS (mbslen, size_t, (const char *string));
 # endif
 _GL_CXXALIASWARN (mbslen);
@@ -737,6 +741,7 @@ _GL_CXXALIASWARN (mbslen);
 /* Return the number of multibyte characters in the character string starting
    at STRING and ending at STRING + LEN.  */
 _GL_EXTERN_C size_t mbsnlen (const char *string, size_t len)
+     _GL_ATTRIBUTE_PURE
      _GL_ARG_NONNULL ((1));
 #endif
 
@@ -750,10 +755,12 @@ _GL_EXTERN_C size_t mbsnlen (const char *string, size_t 
len)
 #   define mbschr rpl_mbschr /* avoid collision with HP-UX function */
 #  endif
 _GL_FUNCDECL_RPL (mbschr, char *, (const char *string, int c)
+                                  _GL_ATTRIBUTE_PURE
                                   _GL_ARG_NONNULL ((1)));
 _GL_CXXALIAS_RPL (mbschr, char *, (const char *string, int c));
 # else
 _GL_FUNCDECL_SYS (mbschr, char *, (const char *string, int c)
+                                  _GL_ATTRIBUTE_PURE
                                   _GL_ARG_NONNULL ((1)));
 _GL_CXXALIAS_SYS (mbschr, char *, (const char *string, int c));
 # endif
@@ -770,10 +777,12 @@ _GL_CXXALIASWARN (mbschr);
 #   define mbsrchr rpl_mbsrchr /* avoid collision with system function */
 #  endif
 _GL_FUNCDECL_RPL (mbsrchr, char *, (const char *string, int c)
+                                   _GL_ATTRIBUTE_PURE
                                    _GL_ARG_NONNULL ((1)));
 _GL_CXXALIAS_RPL (mbsrchr, char *, (const char *string, int c));
 # else
 _GL_FUNCDECL_SYS (mbsrchr, char *, (const char *string, int c)
+                                   _GL_ATTRIBUTE_PURE
                                    _GL_ARG_NONNULL ((1)));
 _GL_CXXALIAS_SYS (mbsrchr, char *, (const char *string, int c));
 # endif
@@ -786,6 +795,7 @@ _GL_CXXALIASWARN (mbsrchr);
    Unlike strstr(), this function works correctly in multibyte locales with
    encodings different from UTF-8.  */
 _GL_EXTERN_C char * mbsstr (const char *haystack, const char *needle)
+     _GL_ATTRIBUTE_PURE
      _GL_ARG_NONNULL ((1, 2));
 #endif
 
@@ -797,6 +807,7 @@ _GL_EXTERN_C char * mbsstr (const char *haystack, const 
char *needle)
    different lengths!
    Unlike strcasecmp(), this function works correctly in multibyte locales.  */
 _GL_EXTERN_C int mbscasecmp (const char *s1, const char *s2)
+     _GL_ATTRIBUTE_PURE
      _GL_ARG_NONNULL ((1, 2));
 #endif
 
@@ -811,6 +822,7 @@ _GL_EXTERN_C int mbscasecmp (const char *s1, const char *s2)
    Unlike strncasecmp(), this function works correctly in multibyte locales.
    But beware that N is not a byte count but a character count!  */
 _GL_EXTERN_C int mbsncasecmp (const char *s1, const char *s2, size_t n)
+     _GL_ATTRIBUTE_PURE
      _GL_ARG_NONNULL ((1, 2));
 #endif
 
@@ -824,6 +836,7 @@ _GL_EXTERN_C int mbsncasecmp (const char *s1, const char 
*s2, size_t n)
    Unlike strncasecmp(), this function works correctly in multibyte
    locales.  */
 _GL_EXTERN_C char * mbspcasecmp (const char *string, const char *prefix)
+     _GL_ATTRIBUTE_PURE
      _GL_ARG_NONNULL ((1, 2));
 #endif
 
@@ -834,6 +847,7 @@ _GL_EXTERN_C char * mbspcasecmp (const char *string, const 
char *prefix)
    strlen (haystack) < strlen (needle) !
    Unlike strcasestr(), this function works correctly in multibyte locales.  */
 _GL_EXTERN_C char * mbscasestr (const char *haystack, const char *needle)
+     _GL_ATTRIBUTE_PURE
      _GL_ARG_NONNULL ((1, 2));
 #endif
 
@@ -844,6 +858,7 @@ _GL_EXTERN_C char * mbscasestr (const char *haystack, const 
char *needle)
    if none exists.
    Unlike strcspn(), this function works correctly in multibyte locales.  */
 _GL_EXTERN_C size_t mbscspn (const char *string, const char *accept)
+     _GL_ATTRIBUTE_PURE
      _GL_ARG_NONNULL ((1, 2));
 #endif
 
@@ -857,10 +872,12 @@ _GL_EXTERN_C size_t mbscspn (const char *string, const 
char *accept)
 #   define mbspbrk rpl_mbspbrk /* avoid collision with HP-UX function */
 #  endif
 _GL_FUNCDECL_RPL (mbspbrk, char *, (const char *string, const char *accept)
+                                   _GL_ATTRIBUTE_PURE
                                    _GL_ARG_NONNULL ((1, 2)));
 _GL_CXXALIAS_RPL (mbspbrk, char *, (const char *string, const char *accept));
 # else
 _GL_FUNCDECL_SYS (mbspbrk, char *, (const char *string, const char *accept)
+                                   _GL_ATTRIBUTE_PURE
                                    _GL_ARG_NONNULL ((1, 2)));
 _GL_CXXALIAS_SYS (mbspbrk, char *, (const char *string, const char *accept));
 # endif
@@ -874,6 +891,7 @@ _GL_CXXALIASWARN (mbspbrk);
    if none exists.
    Unlike strspn(), this function works correctly in multibyte locales.  */
 _GL_EXTERN_C size_t mbsspn (const char *string, const char *reject)
+     _GL_ATTRIBUTE_PURE
      _GL_ARG_NONNULL ((1, 2));
 #endif
 
@@ -993,6 +1011,7 @@ _GL_WARN_ON_USE (strsignal, "strsignal is unportable - "
 #if @GNULIB_STRVERSCMP@
 # if address@hidden@
 _GL_FUNCDECL_SYS (strverscmp, int, (const char *, const char *)
+                                   _GL_ATTRIBUTE_PURE
                                    _GL_ARG_NONNULL ((1, 2)));
 # endif
 _GL_CXXALIAS_SYS (strverscmp, int, (const char *, const char *));
diff --git a/lib/gl/wchar.in.h b/lib/gl/wchar.in.h
index 8c24825..fa37325 100644
--- a/lib/gl/wchar.in.h
+++ b/lib/gl/wchar.in.h
@@ -83,6 +83,14 @@
 #ifndef address@hidden@_WCHAR_H
 #define address@hidden@_WCHAR_H
 
+/* The __attribute__ feature is available in gcc versions 2.5 and later.
+   The attribute __pure__ was added in gcc 2.96.  */
+#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 96)
+# define _GL_ATTRIBUTE_PURE __attribute__ ((__pure__))
+#else
+# define _GL_ATTRIBUTE_PURE /* empty */
+#endif
+
 /* The definitions of _GL_FUNCDECL_RPL etc. are copied here.  */
 
 /* The definition of _GL_ARG_NONNULL is copied here.  */
@@ -135,11 +143,11 @@ typedef int rpl_mbstate_t;
 #   undef btowc
 #   define btowc rpl_btowc
 #  endif
-_GL_FUNCDECL_RPL (btowc, wint_t, (int c));
+_GL_FUNCDECL_RPL (btowc, wint_t, (int c) _GL_ATTRIBUTE_PURE);
 _GL_CXXALIAS_RPL (btowc, wint_t, (int c));
 # else
 #  if address@hidden@
-_GL_FUNCDECL_SYS (btowc, wint_t, (int c));
+_GL_FUNCDECL_SYS (btowc, wint_t, (int c) _GL_ATTRIBUTE_PURE);
 #  endif
 _GL_CXXALIAS_SYS (btowc, wint_t, (int c));
 # endif
@@ -160,12 +168,12 @@ _GL_WARN_ON_USE (btowc, "btowc is unportable - "
 #   undef wctob
 #   define wctob rpl_wctob
 #  endif
-_GL_FUNCDECL_RPL (wctob, int, (wint_t wc));
+_GL_FUNCDECL_RPL (wctob, int, (wint_t wc) _GL_ATTRIBUTE_PURE);
 _GL_CXXALIAS_RPL (wctob, int, (wint_t wc));
 # else
 #  if !defined wctob && address@hidden@
 /* wctob is provided by gnulib, or wctob exists but is not declared.  */
-_GL_FUNCDECL_SYS (wctob, int, (wint_t wc));
+_GL_FUNCDECL_SYS (wctob, int, (wint_t wc) _GL_ATTRIBUTE_PURE);
 #  endif
 _GL_CXXALIAS_SYS (wctob, int, (wint_t wc));
 # endif
@@ -426,12 +434,12 @@ _GL_WARN_ON_USE (wcsnrtombs, "wcsnrtombs is unportable - "
 #   undef wcwidth
 #   define wcwidth rpl_wcwidth
 #  endif
-_GL_FUNCDECL_RPL (wcwidth, int, (wchar_t));
+_GL_FUNCDECL_RPL (wcwidth, int, (wchar_t) _GL_ATTRIBUTE_PURE);
 _GL_CXXALIAS_RPL (wcwidth, int, (wchar_t));
 # else
 #  if address@hidden@
 /* wcwidth exists but is not declared.  */
-_GL_FUNCDECL_SYS (wcwidth, int, (wchar_t));
+_GL_FUNCDECL_SYS (wcwidth, int, (wchar_t) _GL_ATTRIBUTE_PURE);
 #  endif
 _GL_CXXALIAS_SYS (wcwidth, int, (wchar_t));
 # endif
@@ -448,7 +456,8 @@ _GL_WARN_ON_USE (wcwidth, "wcwidth is unportable - "
 /* Search N wide characters of S for C.  */
 #if @GNULIB_WMEMCHR@
 # if address@hidden@
-_GL_FUNCDECL_SYS (wmemchr, wchar_t *, (const wchar_t *s, wchar_t c, size_t n));
+_GL_FUNCDECL_SYS (wmemchr, wchar_t *, (const wchar_t *s, wchar_t c, size_t n)
+                                      _GL_ATTRIBUTE_PURE);
 # endif
   /* On some systems, this function is defined as an overloaded function:
        extern "C++" {
@@ -479,7 +488,8 @@ _GL_WARN_ON_USE (wmemchr, "wmemchr is unportable - "
 #if @GNULIB_WMEMCMP@
 # if address@hidden@
 _GL_FUNCDECL_SYS (wmemcmp, int,
-                  (const wchar_t *s1, const wchar_t *s2, size_t n));
+                  (const wchar_t *s1, const wchar_t *s2, size_t n)
+                  _GL_ATTRIBUTE_PURE);
 # endif
 _GL_CXXALIAS_SYS (wmemcmp, int,
                   (const wchar_t *s1, const wchar_t *s2, size_t n));
@@ -549,7 +559,7 @@ _GL_WARN_ON_USE (wmemset, "wmemset is unportable - "
 /* Return the number of wide characters in S.  */
 #if @GNULIB_WCSLEN@
 # if address@hidden@
-_GL_FUNCDECL_SYS (wcslen, size_t, (const wchar_t *s));
+_GL_FUNCDECL_SYS (wcslen, size_t, (const wchar_t *s) _GL_ATTRIBUTE_PURE);
 # endif
 _GL_CXXALIAS_SYS (wcslen, size_t, (const wchar_t *s));
 _GL_CXXALIASWARN (wcslen);
@@ -565,7 +575,8 @@ _GL_WARN_ON_USE (wcslen, "wcslen is unportable - "
 /* Return the number of wide characters in S, but at most MAXLEN.  */
 #if @GNULIB_WCSNLEN@
 # if address@hidden@
-_GL_FUNCDECL_SYS (wcsnlen, size_t, (const wchar_t *s, size_t maxlen));
+_GL_FUNCDECL_SYS (wcsnlen, size_t, (const wchar_t *s, size_t maxlen)
+                                   _GL_ATTRIBUTE_PURE);
 # endif
 _GL_CXXALIAS_SYS (wcsnlen, size_t, (const wchar_t *s, size_t maxlen));
 _GL_CXXALIASWARN (wcsnlen);
@@ -684,7 +695,8 @@ _GL_WARN_ON_USE (wcsncat, "wcsncat is unportable - "
 /* Compare S1 and S2.  */
 #if @GNULIB_WCSCMP@
 # if address@hidden@
-_GL_FUNCDECL_SYS (wcscmp, int, (const wchar_t *s1, const wchar_t *s2));
+_GL_FUNCDECL_SYS (wcscmp, int, (const wchar_t *s1, const wchar_t *s2)
+                               _GL_ATTRIBUTE_PURE);
 # endif
 _GL_CXXALIAS_SYS (wcscmp, int, (const wchar_t *s1, const wchar_t *s2));
 _GL_CXXALIASWARN (wcscmp);
@@ -701,7 +713,8 @@ _GL_WARN_ON_USE (wcscmp, "wcscmp is unportable - "
 #if @GNULIB_WCSNCMP@
 # if address@hidden@
 _GL_FUNCDECL_SYS (wcsncmp, int,
-                  (const wchar_t *s1, const wchar_t *s2, size_t n));
+                  (const wchar_t *s1, const wchar_t *s2, size_t n)
+                  _GL_ATTRIBUTE_PURE);
 # endif
 _GL_CXXALIAS_SYS (wcsncmp, int,
                   (const wchar_t *s1, const wchar_t *s2, size_t n));
@@ -718,7 +731,8 @@ _GL_WARN_ON_USE (wcsncmp, "wcsncmp is unportable - "
 /* Compare S1 and S2, ignoring case.  */
 #if @GNULIB_WCSCASECMP@
 # if address@hidden@
-_GL_FUNCDECL_SYS (wcscasecmp, int, (const wchar_t *s1, const wchar_t *s2));
+_GL_FUNCDECL_SYS (wcscasecmp, int, (const wchar_t *s1, const wchar_t *s2)
+                                   _GL_ATTRIBUTE_PURE);
 # endif
 _GL_CXXALIAS_SYS (wcscasecmp, int, (const wchar_t *s1, const wchar_t *s2));
 _GL_CXXALIASWARN (wcscasecmp);
@@ -735,7 +749,8 @@ _GL_WARN_ON_USE (wcscasecmp, "wcscasecmp is unportable - "
 #if @GNULIB_WCSNCASECMP@
 # if address@hidden@
 _GL_FUNCDECL_SYS (wcsncasecmp, int,
-                  (const wchar_t *s1, const wchar_t *s2, size_t n));
+                  (const wchar_t *s1, const wchar_t *s2, size_t n)
+                  _GL_ATTRIBUTE_PURE);
 # endif
 _GL_CXXALIAS_SYS (wcsncasecmp, int,
                   (const wchar_t *s1, const wchar_t *s2, size_t n));
@@ -803,7 +818,8 @@ _GL_WARN_ON_USE (wcsdup, "wcsdup is unportable - "
 /* Find the first occurrence of WC in WCS.  */
 #if @GNULIB_WCSCHR@
 # if address@hidden@
-_GL_FUNCDECL_SYS (wcschr, wchar_t *, (const wchar_t *wcs, wchar_t wc));
+_GL_FUNCDECL_SYS (wcschr, wchar_t *, (const wchar_t *wcs, wchar_t wc)
+                                     _GL_ATTRIBUTE_PURE);
 # endif
   /* On some systems, this function is defined as an overloaded function:
        extern "C++" {
@@ -832,7 +848,8 @@ _GL_WARN_ON_USE (wcschr, "wcschr is unportable - "
 /* Find the last occurrence of WC in WCS.  */
 #if @GNULIB_WCSRCHR@
 # if address@hidden@
-_GL_FUNCDECL_SYS (wcsrchr, wchar_t *, (const wchar_t *wcs, wchar_t wc));
+_GL_FUNCDECL_SYS (wcsrchr, wchar_t *, (const wchar_t *wcs, wchar_t wc)
+                                      _GL_ATTRIBUTE_PURE);
 # endif
   /* On some systems, this function is defined as an overloaded function:
        extern "C++" {
@@ -862,7 +879,8 @@ _GL_WARN_ON_USE (wcsrchr, "wcsrchr is unportable - "
    of wide characters not in REJECT.  */
 #if @GNULIB_WCSCSPN@
 # if address@hidden@
-_GL_FUNCDECL_SYS (wcscspn, size_t, (const wchar_t *wcs, const wchar_t 
*reject));
+_GL_FUNCDECL_SYS (wcscspn, size_t, (const wchar_t *wcs, const wchar_t *reject)
+                                   _GL_ATTRIBUTE_PURE);
 # endif
 _GL_CXXALIAS_SYS (wcscspn, size_t, (const wchar_t *wcs, const wchar_t 
*reject));
 _GL_CXXALIASWARN (wcscspn);
@@ -879,7 +897,8 @@ _GL_WARN_ON_USE (wcscspn, "wcscspn is unportable - "
    of wide characters in ACCEPT.  */
 #if @GNULIB_WCSSPN@
 # if address@hidden@
-_GL_FUNCDECL_SYS (wcsspn, size_t, (const wchar_t *wcs, const wchar_t *accept));
+_GL_FUNCDECL_SYS (wcsspn, size_t, (const wchar_t *wcs, const wchar_t *accept)
+                                  _GL_ATTRIBUTE_PURE);
 # endif
 _GL_CXXALIAS_SYS (wcsspn, size_t, (const wchar_t *wcs, const wchar_t *accept));
 _GL_CXXALIASWARN (wcsspn);
@@ -896,7 +915,8 @@ _GL_WARN_ON_USE (wcsspn, "wcsspn is unportable - "
 #if @GNULIB_WCSPBRK@
 # if address@hidden@
 _GL_FUNCDECL_SYS (wcspbrk, wchar_t *,
-                  (const wchar_t *wcs, const wchar_t *accept));
+                  (const wchar_t *wcs, const wchar_t *accept)
+                  _GL_ATTRIBUTE_PURE);
 # endif
   /* On some systems, this function is defined as an overloaded function:
        extern "C++" {
@@ -928,7 +948,8 @@ _GL_WARN_ON_USE (wcspbrk, "wcspbrk is unportable - "
 #if @GNULIB_WCSSTR@
 # if address@hidden@
 _GL_FUNCDECL_SYS (wcsstr, wchar_t *,
-                  (const wchar_t *haystack, const wchar_t *needle));
+                  (const wchar_t *haystack, const wchar_t *needle)
+                  _GL_ATTRIBUTE_PURE);
 # endif
   /* On some systems, this function is defined as an overloaded function:
        extern "C++" {
@@ -982,11 +1003,13 @@ _GL_WARN_ON_USE (wcstok, "wcstok is unportable - "
 #   undef wcswidth
 #   define wcswidth rpl_wcswidth
 #  endif
-_GL_FUNCDECL_RPL (wcswidth, int, (const wchar_t *s, size_t n));
+_GL_FUNCDECL_RPL (wcswidth, int, (const wchar_t *s, size_t n)
+                                 _GL_ATTRIBUTE_PURE);
 _GL_CXXALIAS_RPL (wcswidth, int, (const wchar_t *s, size_t n));
 # else
 #  if address@hidden@
-_GL_FUNCDECL_SYS (wcswidth, int, (const wchar_t *s, size_t n));
+_GL_FUNCDECL_SYS (wcswidth, int, (const wchar_t *s, size_t n)
+                                 _GL_ATTRIBUTE_PURE);
 #  endif
 _GL_CXXALIAS_SYS (wcswidth, int, (const wchar_t *s, size_t n));
 # endif
diff --git a/lib/gltests/fpucw.h b/lib/gltests/fpucw.h
index a62c51d..23e4c81 100644
--- a/lib/gltests/fpucw.h
+++ b/lib/gltests/fpucw.h
@@ -30,7 +30,8 @@
 
    On some platforms, such as NetBSD, the default precision is set to
    "double precision".  This means that 'long double' instructions will operate
-   only as 'double', i.e. lead wrong results.
+   only as 'double', i.e. lead to wrong results.  Similarly on FreeBSD 6.4, at
+   least for the division of 'long double' numbers.
 
    The FPU control word is under control of the application, i.e. it is
    not required to be set either way by the ABI.  (In fact, the i386 ABI
diff --git a/lib/gltests/macros.h b/lib/gltests/macros.h
index 77a92f8..478004c 100644
--- a/lib/gltests/macros.h
+++ b/lib/gltests/macros.h
@@ -66,3 +66,8 @@
 /* STREQ (str1, str2)
    Return true if two strings compare equal.  */
 #define STREQ(a, b) (strcmp (a, b) == 0)
+
+/* Some numbers in the interval [0,1).  */
+extern const float randomf[1000];
+extern const double randomd[1000];
+extern const long double randoml[1000];
diff --git a/lib/maint.mk b/lib/maint.mk
index 4cbd5f4..951b358 100644
--- a/lib/maint.mk
+++ b/lib/maint.mk
@@ -455,7 +455,8 @@ sc_prohibit_quotearg_without_use:
 
 # Don't include quote.h unless you use one of its functions.
 sc_prohibit_quote_without_use:
-       @h='quote.h' re='\<quote(_n)? *\(' $(_sc_header_without_use)
+       @h='quote.h' re='\<quote((_n)? *\(|_quoting_options\>)' \
+         $(_sc_header_without_use)
 
 # Don't include this header unless you use one of its functions.
 sc_prohibit_long_options_without_use:
@@ -1332,7 +1333,7 @@ alpha beta stable: $(local-check) writable-files 
$(submodule-checks)
        $(MAKE) vc-diff-check
        $(MAKE) news-check
        $(MAKE) distcheck
-       $(MAKE) dist XZ_OPT=-9ev
+       $(MAKE) dist
        $(MAKE) $(release-prep-hook) RELEASE_TYPE=$@
        $(MAKE) -s emit_upload_commands RELEASE_TYPE=$@
 
diff --git a/lib/openid20/client.c b/lib/openid20/client.c
index 95836d7..310111d 100644
--- a/lib/openid20/client.c
+++ b/lib/openid20/client.c
@@ -72,14 +72,13 @@ _gsasl_openid20_client_step (Gsasl_session * sctx,
     case 0:
       {
        const char *authzid = gsasl_property_get (sctx, GSASL_AUTHZID);
-       const char *p;
+       const char *authid = gsasl_property_get (sctx, GSASL_AUTHID);
 
-       p = gsasl_property_get (sctx, GSASL_AUTHID);
-       if (!p || !*p)
+       if (!authid || !*authid)
          return GSASL_NO_AUTHID;
 
        res = _gsasl_gs2_generate_header (false, 'n', NULL, authzid,
-                                         strlen (p), p,
+                                         strlen (authid), authid,
                                          output, output_len);
        if (res != GSASL_OK)
          return res;
@@ -101,33 +100,55 @@ _gsasl_openid20_client_step (Gsasl_session * sctx,
 
        *output_len = 1;
        *output = strdup ("=");
+       if (!*output)
+         return GSASL_MALLOC_ERROR;
 
        res = GSASL_OK;
        state->step++;
       }
       break;
 
-      /* optional */
+      /* This step is optional.  The server could have approved
+        authentication already.  Alternatively, it wanted to send
+        some SREGs or error data and we end up here. */
     case 2:
       {
        gsasl_property_set_raw (sctx, GSASL_OPENID20_OUTCOME_DATA,
                                input, input_len);
 
-       *output_len = 0;
-       *output = NULL;
-
        /* In the case of failures, the response MUST follow this
           syntax:
 
           outcome_data = "openid.error" "=" sreg_val *( "," sregp_avp )
+
+          [RFC4422] Section 3.6 explicitly prohibits additional information in
+          an unsuccessful authentication outcome.  Therefore, the openid.error
+          and openid.error_code are to be sent as an additional challenge in
+          the event of an unsuccessful outcome.  In this case, as the protocol
+          is lock step,  the client will follow with an additional exchange
+          containing "=", after which the server will respond with an
+          application-level outcome.
        */
 
 #define ERR_PREFIX "openid.error="
        if (input_len > strlen (ERR_PREFIX)
            && strncmp (ERR_PREFIX, input, strlen (ERR_PREFIX)) == 0)
-         res = GSASL_AUTHENTICATION_ERROR;
+         {
+           *output_len = 1;
+           *output = strdup ("=");
+           if (!*output)
+             return GSASL_MALLOC_ERROR;
+
+           res = GSASL_NEEDS_MORE;
+         }
        else
-         res = GSASL_OK;
+         {
+           *output_len = 0;
+           *output = NULL;
+
+           res = GSASL_OK;
+         }
+
        state->step++;
       }
       break;
diff --git a/lib/openid20/server.c b/lib/openid20/server.c
index 200a2da..d1cf7a5 100644
--- a/lib/openid20/server.c
+++ b/lib/openid20/server.c
@@ -39,7 +39,7 @@
 struct openid20_server_state
 {
   int step;
-  int validation_res;
+  int allow_error_step;
 };
 
 int
@@ -51,8 +51,6 @@ _gsasl_openid20_server_start (Gsasl_session * sctx, void 
**mech_data)
   if (state == NULL)
     return GSASL_MALLOC_ERROR;
 
-  state->validation_res = GSASL_AUTHENTICATION_ERROR;
-
   *mech_data = state;
 
   return GSASL_OK;
@@ -136,9 +134,12 @@ _gsasl_openid20_server_step (Gsasl_session * sctx,
               is lock step, the client will follow with an additional
               exchange containing "=", after which the server will
               respond with an application-level outcome. */
+
+           state->allow_error_step = 1;
+           state->step++;
            return GSASL_NEEDS_MORE;
          }
-
+       
        outcome_data = gsasl_property_get (sctx, GSASL_OPENID20_OUTCOME_DATA);
        if (outcome_data)
          {
@@ -153,17 +154,23 @@ _gsasl_openid20_server_step (Gsasl_session * sctx,
            *output_len = 0;
          }
 
-       state->validation_res = res = GSASL_OK;
+       res = GSASL_OK;
        state->step++;
       }
       break;
 
     case 2:
       {
-       if (!(input_len == 0 && *input == '\0'))
+       /* We only get here when the previous step signalled an error
+          to the client.  */
+
+       if (!state->allow_error_step)
+         return GSASL_MECHANISM_CALLED_TOO_MANY_TIMES;
+
+       if (!(input_len == 1 && *input == '='))
          return GSASL_MECHANISM_PARSE_ERROR;
 
-       res = state->validation_res;
+       res = GSASL_AUTHENTICATION_ERROR;
        state->step++;
       }
       break;
diff --git a/maint.mk b/maint.mk
index 4cbd5f4..951b358 100644
--- a/maint.mk
+++ b/maint.mk
@@ -455,7 +455,8 @@ sc_prohibit_quotearg_without_use:
 
 # Don't include quote.h unless you use one of its functions.
 sc_prohibit_quote_without_use:
-       @h='quote.h' re='\<quote(_n)? *\(' $(_sc_header_without_use)
+       @h='quote.h' re='\<quote((_n)? *\(|_quoting_options\>)' \
+         $(_sc_header_without_use)
 
 # Don't include this header unless you use one of its functions.
 sc_prohibit_long_options_without_use:
@@ -1332,7 +1333,7 @@ alpha beta stable: $(local-check) writable-files 
$(submodule-checks)
        $(MAKE) vc-diff-check
        $(MAKE) news-check
        $(MAKE) distcheck
-       $(MAKE) dist XZ_OPT=-9ev
+       $(MAKE) dist
        $(MAKE) $(release-prep-hook) RELEASE_TYPE=$@
        $(MAKE) -s emit_upload_commands RELEASE_TYPE=$@
 
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 4c52fdb..fca6b0f 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -42,7 +42,8 @@ TESTS_ENVIRONMENT = \
        $(VALGRIND)
 
 ctests = external cram-md5 digest-md5 md5file name errors suggest      \
-       simple crypto scram scramplus symbols readnz gssapi gs2-krb5 saml20
+       simple crypto scram scramplus symbols readnz gssapi gs2-krb5    \
+       saml20 openid20
 if OBSOLETE
 ctests += old-simple old-md5file old-cram-md5 old-digest-md5   \
        old-base64
diff --git a/tests/openid20.c b/tests/openid20.c
new file mode 100644
index 0000000..3f9ba68
--- /dev/null
+++ b/tests/openid20.c
@@ -0,0 +1,326 @@
+/* openid20.c --- Test the OPENID20 mechanism.
+ * Copyright (C) 2010-2012 Simon Josefsson
+ *
+ * This file is part of GNU SASL.
+ *
+ * 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/>.
+ *
+ */
+
+#include <config.h>
+
+#include <stdio.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "utils.h"
+
+const char *authzid = NULL;
+const char *sreg = NULL;
+int validation_res = GSASL_OK;
+int expect_server_res = GSASL_OK;
+int expect_client_res = GSASL_OK;
+int expect_server2_res = GSASL_MECHANISM_CALLED_TOO_MANY_TIMES;
+
+static int
+client_callback (Gsasl * ctx, Gsasl_session * sctx, Gsasl_property prop)
+{
+  int rc = GSASL_NO_CALLBACK;
+
+  switch (prop)
+    {
+    case GSASL_AUTHZID:
+      if (authzid)
+       gsasl_property_set (sctx, prop, authzid);
+      rc = GSASL_OK;
+      break;
+
+    case GSASL_AUTHID:
+      gsasl_property_set (sctx, prop, "http://user.example.org/";);
+      rc = GSASL_OK;
+      break;
+
+    case GSASL_OPENID20_AUTHENTICATE_IN_BROWSER:
+      rc = GSASL_OK;
+      break;
+
+    default:
+      fail ("Unknown client callback property %d\n", prop);
+      break;
+    }
+
+  return rc;
+}
+
+static int
+server_callback (Gsasl * ctx, Gsasl_session * sctx, Gsasl_property prop)
+{
+  int rc = GSASL_NO_CALLBACK;
+
+  switch (prop)
+    {
+    case GSASL_OPENID20_REDIRECT_URL:
+      gsasl_property_set (sctx, prop,
+                         "http://idp.example/NONCE/?openid.foo=bar";);
+      rc = GSASL_OK;
+      break;
+
+    case GSASL_VALIDATE_OPENID20:
+      rc = validation_res;
+      break;
+
+    case GSASL_OPENID20_OUTCOME_DATA:
+      if (sreg)
+       gsasl_property_set (sctx, prop, sreg);
+      rc = GSASL_OK;
+      break;
+
+    default:
+      fail ("Unknown server callback property %d\n", prop);
+      break;
+    }
+
+  return rc;
+}
+
+static void
+openid20 (Gsasl * c, Gsasl * s)
+{
+  Gsasl_session *client, *server;
+  char *s1, *s2;
+  int res;
+
+  /* Simple client */
+
+  res = gsasl_client_start (c, "OPENID20", &client);
+  if (res != GSASL_OK)
+    {
+      fail ("gsasl_client_start (%d):\n%s\n", res, gsasl_strerror (res));
+      return;
+    }
+
+  res = gsasl_server_start (s, "OPENID20", &server);
+  if (res != GSASL_OK)
+    {
+      fail ("gsasl_server_start (%d):\n%s\n", res, gsasl_strerror (res));
+      return;
+    }
+
+  /* OPENID20 is client-first.  Check that server just waits. */
+
+  res = gsasl_step64 (server, NULL, &s2);
+  if (res != GSASL_NEEDS_MORE)
+    {
+      fail ("gsasl_step server0 (%d):\n%s\n", res, gsasl_strerror (res));
+      return;
+    }
+
+  if (debug)
+    printf ("S: `%s' (%d) %s\n", s2 ? s2 : "", (int) strlen (s2),
+           gsasl_strerror_name (res));
+
+  /* The client should send the OpenID URL. */
+
+  res = gsasl_step64 (client, s2, &s1);
+  gsasl_free (s2);
+  if (res != GSASL_NEEDS_MORE)
+    {
+      fail ("gsasl_step client1 (%d):\n%s\n", res, gsasl_strerror (res));
+      return;
+    }
+
+  if (debug)
+    printf ("C: `%s' (%d) %s\n", s1 ? s1 : "", (int) strlen (s1),
+           gsasl_strerror_name (res));
+
+  /* The server should send the redirect URL. */
+
+  res = gsasl_step64 (server, s1, &s2);
+  gsasl_free (s1);
+  if (res != GSASL_NEEDS_MORE)
+    {
+      fail ("gsasl_step server1 (%d):\n%s\n", res, gsasl_strerror (res));
+      return;
+    }
+
+  if (debug)
+    printf ("S: `%s' (%d) %s\n", s2 ? s2 : "", (int) strlen (s2),
+           gsasl_strerror_name (res));
+
+  /* The client sends '='. */
+
+  res = gsasl_step64 (client, s2, &s1);
+  gsasl_free (s2);
+  if (res != GSASL_OK)
+    {
+      fail ("gsasl_step client2 (%d):\n%s\n", res, gsasl_strerror (res));
+      return;
+    }
+
+  if (debug)
+    printf ("C: `%s' (%d) %s\n", s1 ? s1 : "", (int) strlen (s1),
+           gsasl_strerror_name (res));
+
+  /* Now the server sends the outcome_data */
+
+  res = gsasl_step64 (server, s1, &s2);
+  gsasl_free (s1);
+  if (res != expect_server_res)
+    {
+      fail ("gsasl_step server2 (%d):\n%s\n", res, gsasl_strerror (res));
+      return;
+    }
+
+  if (res == GSASL_OK || res == GSASL_NEEDS_MORE)
+    {
+      if (debug)
+       printf ("S: `%s' (%d) %s\n", s2 ? s2 : "", (int) strlen (s2),
+               gsasl_strerror_name (res));
+    }
+
+  /* The client receives the outcome data and sends a empty packet. */
+
+  res = gsasl_step64 (client, s2, &s1);
+  gsasl_free (s2);
+  if (res != expect_client_res)
+    {
+      fail ("gsasl_step client3 (%d):\n%s\n", res, gsasl_strerror (res));
+      return;
+    }
+
+  if (res == GSASL_OK || res == GSASL_NEEDS_MORE)
+    {
+      if (debug)
+       printf ("C: `%s' (%d) %s\n", s1 ? s1 : "", (int) strlen (s1),
+               gsasl_strerror_name (res));
+    }
+  else if (debug)
+    {
+      printf ("C: %s\n", gsasl_strerror_name (res));
+      s1 = NULL;
+    }
+
+  /* The server should reject authentication at this point */
+
+  res = gsasl_step64 (server, s1, &s2);
+  gsasl_free (s1);
+  if (res != expect_server2_res)
+    {
+      fail ("gsasl_step server3 (%d):\n%s\n", res, gsasl_strerror (res));
+      return;
+    }
+
+  if (res == GSASL_OK || res == GSASL_NEEDS_MORE)
+    {
+      if (debug)
+       printf ("S: `%s' (%d) %s\n", s2 ? s2 : "", (int) strlen (s2),
+               gsasl_strerror_name (res));
+    }
+  else if (debug)
+    {
+      printf ("S: %s\n", gsasl_strerror_name (res));
+      s2 = NULL;
+    }
+
+  /* The client should be called too many times now */
+
+  res = gsasl_step64 (client, s2, &s1);
+  gsasl_free (s2);
+  if (res != GSASL_MECHANISM_CALLED_TOO_MANY_TIMES)
+    {
+      fail ("gsasl_step client4 (%d):\n%s\n", res, gsasl_strerror (res));
+      return;
+    }
+
+  if (debug)
+    printf ("C: %s\n", gsasl_strerror_name (res));
+
+  if (authzid == NULL && gsasl_property_fast (server, GSASL_AUTHZID) == NULL)
+    success ("expected and got no authzid\n");
+  else if (!authzid && gsasl_property_fast (server, GSASL_AUTHZID))
+    fail ("got unexpected authzid? %s\n",
+         gsasl_property_fast (server, GSASL_AUTHZID));
+  else if (authzid && !gsasl_property_fast (server, GSASL_AUTHZID))
+    fail ("did not get authzid? %s\n", authzid);
+  else if (strcmp (authzid, gsasl_property_fast (server, GSASL_AUTHZID)) != 0)
+    fail ("authzid comparison failed: got %s expected %s\n",
+         gsasl_property_fast (server, GSASL_AUTHZID), authzid);
+
+  gsasl_finish (client);
+  gsasl_finish (server);
+}
+
+void
+doit (void)
+{
+  Gsasl *c = NULL, *s = NULL;
+  int res;
+
+  res = gsasl_init (&c);
+  if (res != GSASL_OK)
+    {
+      fail ("gsasl_init() failed (%d):\n%s\n", res, gsasl_strerror (res));
+      return;
+    }
+
+  res = gsasl_init (&s);
+  if (res != GSASL_OK)
+    {
+      fail ("gsasl_init() failed (%d):\n%s\n", res, gsasl_strerror (res));
+      return;
+    }
+
+  if (!gsasl_client_support_p (c, "OPENID20"))
+    {
+      gsasl_done (c);
+      fail ("No support for OPENID20 clients.\n");
+      exit (77);
+    }
+
+  if (!gsasl_server_support_p (s, "OPENID20"))
+    {
+      gsasl_done (s);
+      fail ("No support for OPENID20 servers.\n");
+      exit (77);
+    }
+
+  gsasl_callback_set (c, client_callback);
+  gsasl_callback_set (s, server_callback);
+
+  printf ("Running successful authentication without SREG.\n");
+  openid20 (c, s);
+
+  printf ("Running successful authentication with SREG.\n");
+  sreg = "nickname=jas";
+  openid20 (c, s);
+
+  authzid = "user";
+  printf ("Running successful authentication without SREG with authzid.\n");
+  openid20 (c, s);
+
+  printf ("Running successful authentication with SREG with authzid.\n");
+  sreg = "nickname=jas";
+  openid20 (c, s);
+
+  printf ("Running failed authentication.\n");
+  validation_res = GSASL_AUTHENTICATION_ERROR;
+  expect_server_res = GSASL_NEEDS_MORE;
+  expect_client_res = GSASL_NEEDS_MORE;
+  expect_server2_res = GSASL_AUTHENTICATION_ERROR;
+  openid20 (c, s);
+
+  gsasl_done (c);
+  gsasl_done (s);
+}


hooks/post-receive
-- 
GNU gsasl



reply via email to

[Prev in Thread] Current Thread [Next in Thread]