New module 'memxfrm'.
authorBruno Haible <bruno@clisp.org>
Sat, 7 Mar 2009 12:38:02 +0000 (13:38 +0100)
committerBruno Haible <bruno@clisp.org>
Sat, 7 Mar 2009 12:38:02 +0000 (13:38 +0100)
ChangeLog
lib/memxfrm.c [new file with mode: 0644]
lib/memxfrm.h [new file with mode: 0644]
modules/memxfrm [new file with mode: 0644]

index 2335ec71bafcecdcbe88c9c7fe4a780fa71cb4b4..8056e4cf02cadba23f7df36a72e54c7207ac2532 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,10 @@
+2009-03-07  Bruno Haible  <bruno@clisp.org>
+
+       New module 'memxfrm'.
+       * lib/memxfrm.h: New file.
+       * lib/memxfrm.c: New file.
+       * modules/memxfrm: New file.
+
 2009-03-07  Bruno Haible  <bruno@clisp.org>
 
        New module 'memcmp2'.
diff --git a/lib/memxfrm.c b/lib/memxfrm.c
new file mode 100644 (file)
index 0000000..9b29c52
--- /dev/null
@@ -0,0 +1,122 @@
+/* Locale dependent memory area transformation for comparison.
+   Copyright (C) 2009 Free Software Foundation, Inc.
+   Written by Bruno Haible <bruno@clisp.org>, 2009.
+
+   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 <http://www.gnu.org/licenses/>.  */
+
+#include <config.h>
+
+/* Specification.  */
+#include "memxfrm.h"
+
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+
+char *
+memxfrm (char *s, size_t n, size_t *lengthp)
+{
+  /* Result accumulator.  */
+  char *result;
+  size_t length;
+  size_t allocated;
+
+  char orig_sentinel;
+
+  /* Initial memory allocation.  */
+  allocated = (n > 0 ? n : 1);
+  result = (char *) malloc (allocated);
+  if (result == NULL)
+    goto out_of_memory_2;
+  length = 0;
+
+  /* Add sentinel.byte.  */
+  orig_sentinel = s[n];
+  s[n] = '\0';
+
+  /* Iterate through S, transforming each NUL terminated segment.
+     Accumulate the resulting transformed segments in result, separated by
+     NULs.  */
+  {
+    const char *p_end = s + n + 1;
+    const char *p;
+
+    p = s;
+    for (;;)
+      {
+       /* Search next NUL byte.  */
+       const char *q = p + strlen (p);
+
+       for (;;)
+         {
+           size_t k;
+
+           errno = 0;
+           k = strxfrm (result + length, p, allocated - length);
+           if (errno != 0)
+             goto fail;
+           if (k >= allocated - length)
+             {
+               /* Grow the result buffer.  */
+               char *new_result;
+
+               allocated = 2 * allocated;
+               new_result = (char *) realloc (result, allocated);
+               if (new_result == NULL)
+                 goto out_of_memory_1;
+               result = new_result;
+             }
+           else
+             {
+               length += k;
+               break;
+             }
+         }
+
+       p = q + 1;
+       if (p == p_end)
+         break;
+       result[length] = '\0';
+        length++;
+      }
+  }
+
+  /* Shrink the allocated memory if possible.  */
+  if ((length > 0 ? length : 1) < allocated)
+    {
+      char *memory = (char *) realloc (result, length > 0 ? length : 1);
+      if (memory != NULL)
+       result = memory;
+    }
+
+  s[n] = orig_sentinel;
+  *lengthp = length;
+  return result;
+
+ fail:
+  {
+    int saved_errno = errno;
+    free (result);
+    s[n] = orig_sentinel;
+    errno = saved_errno;
+    return NULL;
+  }
+
+ out_of_memory_1:
+  free (result);
+  s[n] = orig_sentinel;
+ out_of_memory_2:
+  errno = ENOMEM;
+  return NULL;
+}
diff --git a/lib/memxfrm.h b/lib/memxfrm.h
new file mode 100644 (file)
index 0000000..6354633
--- /dev/null
@@ -0,0 +1,46 @@
+/* Locale dependent memory area transformation for comparison.
+   Copyright (C) 2009 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 <http://www.gnu.org/licenses/>.  */
+
+#ifndef MEMXFRM_H
+#define MEMXFRM_H
+
+#include <stddef.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/* Generalization of strxfrm() to strings with embedded NUL bytes.  */
+
+/* Transform the memory area [S..S+N-1] to a memory area, in such a way that
+   comparing (S1,N1) and (S2,N2) with memcoll() is equivalent to comparing
+   memxfrm(S1,N1) and memxfrm(S2,N2) with memcmp2().
+   The byte S[N] may be temporarily overwritten by this function, but will be
+   restored before this function returns.
+   The result of this function depends on the LC_COLLATE category of the
+   current locale.
+   If successful, return the freshly allocated transformed string and set
+   *LENGTHP to its length,
+   Upon failure, return NULL, with errno set.  */
+extern char * memxfrm (char *s, size_t n, size_t *lengthp);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* MEMXFRM_H */
diff --git a/modules/memxfrm b/modules/memxfrm
new file mode 100644 (file)
index 0000000..8c9033c
--- /dev/null
@@ -0,0 +1,22 @@
+Description:
+Locale dependent memory area transformation for comparison.
+
+Files:
+lib/memxfrm.h
+lib/memxfrm.c
+
+Depends-on:
+
+configure.ac:
+
+Makefile.am:
+lib_SOURCES += memxfrm.c
+
+Include:
+"memxfrm.h"
+
+License:
+LGPL
+
+Maintainer:
+Bruno Haible