From: Bruno Haible Date: Sat, 14 Aug 2010 22:19:47 +0000 (+0200) Subject: New module 'astrxfrm'. X-Git-Tag: v0.1~3932 X-Git-Url: http://erislabs.net/gitweb/?p=gnulib.git;a=commitdiff_plain;h=4e48756921cae0aec44afad18bfaa881890e6142 New module 'astrxfrm'. --- diff --git a/ChangeLog b/ChangeLog index 68df573c7..d78f6ff07 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,10 @@ +2010-08-14 Bruno Haible + + New module 'astrxfrm'. + * lib/astrxfrm.h: New file. + * lib/astrxfrm.c: New file, based on lib/memxfrm.c. + * modules/astrxfrm: New file. + 2010-08-14 Reuben Thomas regex: Tweak doc. diff --git a/lib/astrxfrm.c b/lib/astrxfrm.c new file mode 100644 index 000000000..00315bbac --- /dev/null +++ b/lib/astrxfrm.c @@ -0,0 +1,181 @@ +/* Locale dependent string transformation for comparison. + Copyright (C) 2010 Free Software Foundation, Inc. + Written by Bruno Haible , 2010. + + This program is free software: you can redistribute it and/or modify it + under the terms of the GNU Lesser 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with this program. If not, see . */ + +#include + +/* Specification. */ +#include "astrxfrm.h" + +#include +#include +#include + +char * +astrxfrm (const char *s, char *resultbuf, size_t *lengthp) +{ + char tmpbuf[4000]; + char *result; /* either == resultbuf or == tmpbuf or freshly allocated + or NULL. */ + size_t allocated; /* number of bytes allocated at result */ + size_t length; + + if (resultbuf != NULL) + { + result = resultbuf; + allocated = *lengthp; + } + else + { + result = NULL; + allocated = 0; + } + + { + size_t l = strlen (s); + size_t k; + + /* A call to strxfrm costs about 20 times more than a call to strdup of + the result. Therefore it is worth to try to avoid calling strxfrm + more than once on a given string, by making enough room before calling + strxfrm. The size of the strxfrm result, k, is likely to be between + l and 3 * l. */ + if (3 * l + 1 > allocated) + { + /* Grow the result buffer. */ + if (3 * l + 1 <= sizeof (tmpbuf)) + { + result = tmpbuf; + allocated = sizeof (tmpbuf); + } + else + { + size_t new_allocated; + char *new_result; + + new_allocated = 3 * l + 1; + if (new_allocated < 2 * allocated) + new_allocated = 2 * allocated; + new_result = (char *) malloc (new_allocated); + if (new_result != NULL) + { + allocated = new_allocated; + result = new_result; + } + } + } + + errno = 0; + k = strxfrm (result, s, allocated); + if (errno != 0) + goto fail; + if (k >= allocated) + { + /* Grow the result buffer. */ + if (result != resultbuf && result != tmpbuf) + free (result); + if (k + 1 <= sizeof (tmpbuf)) + { + result = tmpbuf; + allocated = sizeof (tmpbuf); + } + else + { + size_t new_allocated; + char *new_result; + + new_allocated = k + 1; + new_result = (char *) malloc (new_allocated); + if (new_result == NULL) + goto out_of_memory; + allocated = new_allocated; + result = new_result; + } + /* Here k < allocated. */ + + /* Try again. */ + errno = 0; + if (strxfrm (result, s, allocated) != k) + /* strxfrm() is not producing reproducible results. */ + abort (); + if (errno != 0) + goto fail; + } + + /* Verify that strxfrm() has NUL-terminated the result. */ + if (result[k] != '\0') + abort (); + length = k + 1; + } + + /* Here length > 0. */ + + if (result == tmpbuf) + { + if (resultbuf != NULL && length <= *lengthp) + { + memcpy (resultbuf, result, length); + result = resultbuf; + } + else + { + char *memory = (char *) malloc (length); + + if (memory == NULL) + goto out_of_memory; + memcpy (memory, result, length); + result = memory; + } + } + else + { + /* Shrink the allocated memory if possible. */ + if (result != resultbuf && length < allocated) + { + if (length <= *lengthp) + { + memcpy (resultbuf, result, length); + free (result); + result = resultbuf; + } + else + { + char *memory = (char *) realloc (result, length); + if (memory != NULL) + { + memcpy (memory, result, length); + result = memory; + } + } + } + } + + *lengthp = length; + return result; + + fail: + { + int saved_errno = errno; + if (result != resultbuf && result != tmpbuf) + free (result); + errno = saved_errno; + return NULL; + } + + out_of_memory: + errno = ENOMEM; + return NULL; +} diff --git a/lib/astrxfrm.h b/lib/astrxfrm.h new file mode 100644 index 000000000..41046a4e5 --- /dev/null +++ b/lib/astrxfrm.h @@ -0,0 +1,47 @@ +/* Locale dependent string transformation for comparison. + Copyright (C) 2010 Free Software Foundation, Inc. + + This program is free software: you can redistribute it and/or modify it + under the terms of the GNU Lesser 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with this program. If not, see . */ + +#ifndef ASTRXFRM_H +#define ASTRXFRM_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + + +/* Variant of strxfrm() with a calling convention that reduces the number + of strxfrm calls. */ + +/* Transform the string starting at S to a string, in such a way that + comparing S1 and S2 with strcoll() is equivalent to comparing astrxfrm(S1) + and astrxfrm(S2) with strcmp(). + The result of this function depends on the LC_COLLATE category of the + current locale. + If successful: If resultbuf is not NULL and the result fits into *lengthp + bytes, it is put in resultbuf, and resultbuf is returned. Otherwise, a + freshly allocated string is returned. In both cases, *lengthp is set to the + length of the returned string. + Upon failure, return NULL, with errno set. */ +extern char * astrxfrm (const char *s, char *resultbuf, size_t *lengthp); + + +#ifdef __cplusplus +} +#endif + +#endif /* ASTRXFRM_H */ diff --git a/modules/astrxfrm b/modules/astrxfrm new file mode 100644 index 000000000..ff7cfa5c9 --- /dev/null +++ b/modules/astrxfrm @@ -0,0 +1,22 @@ +Description: +Locale dependent string transformation for comparison. + +Files: +lib/astrxfrm.h +lib/astrxfrm.c + +Depends-on: + +configure.ac: + +Makefile.am: +lib_SOURCES += astrxfrm.c + +Include: +"astrxfrm.h" + +License: +LGPL + +Maintainer: +Bruno Haible