diff options
Diffstat (limited to 'gnulib/lib/mbmemcasecoll.c')
m--------- | gnulib | 0 | ||||
-rw-r--r-- | gnulib/lib/mbmemcasecoll.c | 190 |
2 files changed, 190 insertions, 0 deletions
diff --git a/gnulib b/gnulib deleted file mode 160000 -Subproject 443bc5ffcf7429e557f4a371b0661abe98ddbc1 diff --git a/gnulib/lib/mbmemcasecoll.c b/gnulib/lib/mbmemcasecoll.c new file mode 100644 index 0000000..76694cb --- /dev/null +++ b/gnulib/lib/mbmemcasecoll.c @@ -0,0 +1,190 @@ +/* Locale-specific case-ignoring memory comparison. + Copyright (C) 2001, 2009-2011 Free Software Foundation, Inc. + Written by Bruno Haible <bruno@clisp.org>, 2001. + + 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 "mbmemcasecoll.h" + +#include <errno.h> +#include <stdlib.h> +#include <string.h> + +/* Get tolower(). */ +#include <ctype.h> + +/* Get mbstate_t, mbrtowc(), wcrtomb(). */ +#include <wchar.h> + +/* Get towlower(). */ +#include <wctype.h> + +#include "malloca.h" +#include "memcmp2.h" +#include "memcoll.h" + +#define TOLOWER(Ch) (isupper (Ch) ? tolower (Ch) : (Ch)) + +/* Apply towlower() to the multibyte character sequence in INBUF, storing the + result as a multibyte character sequence in OUTBUF. */ +static size_t +apply_towlower (const char *inbuf, size_t inbufsize, + char *outbuf, size_t outbufsize) +{ + char *outbuf_orig = outbuf; + size_t remaining; + + remaining = inbufsize; + while (remaining > 0) + { + wchar_t wc1; + size_t n1; + mbstate_t state; + + memset (&state, '\0', sizeof (mbstate_t)); + n1 = mbrtowc (&wc1, inbuf, remaining, &state); + if (n1 == (size_t)(-2)) + break; + if (n1 != (size_t)(-1)) + { + wint_t wc2; + + if (n1 == 0) /* NUL character? */ + n1 = 1; + + wc2 = towlower (wc1); + if (wc2 != wc1) + { + size_t n2; + + memset (&state, '\0', sizeof (mbstate_t)); + n2 = wcrtomb (outbuf, wc2, &state); + if (n2 != (size_t)(-1)) + { + /* Store the translated multibyte character. */ + inbuf += n1; + remaining -= n1; + outbuf += n2; + continue; + } + } + + /* Nothing to translate. */ + memcpy (outbuf, inbuf, n1); + inbuf += n1; + remaining -= n1; + outbuf += n1; + continue; + } + + /* Invalid multibyte character on input. + Copy one byte without modification. */ + *outbuf++ = *inbuf++; + remaining -= 1; + } + /* Incomplete multibyte sequence on input. + Pass it through unmodified. */ + while (remaining > 0) + { + *outbuf++ = *inbuf++; + remaining -= 1; + } + + /* Verify the output buffer was large enough. */ + if (outbuf - outbuf_orig > outbufsize) + abort (); + + /* Return the number of written output bytes. */ + return outbuf - outbuf_orig; +} + +/* Apply tolower() to the unibyte character sequence in INBUF, storing the + result as a unibyte character sequence in OUTBUF. */ +static void +apply_tolower (const char *inbuf, char *outbuf, size_t bufsize) +{ + for (; bufsize > 0; bufsize--) + { + *outbuf = TOLOWER ((unsigned char) *inbuf); + inbuf++; + outbuf++; + } +} + +int +mbmemcasecoll (const char *s1, size_t s1len, const char *s2, size_t s2len, + bool hard_LC_COLLATE) +{ + char *t1; + size_t t1len; + char *t2; + size_t t2len; + char *memory; + int cmp; + + if (MB_CUR_MAX > 1) + { + /* Application of towlower grows each character by a factor 2 + at most. */ + t1len = 2 * s1len; + t2len = 2 * s2len; + } + else + { + /* Application of tolower doesn't change the size. */ + t1len = s1len; + t2len = s2len; + } + /* Allocate memory for t1 and t2. */ + memory = (char *) malloca (t1len + 1 + t2len + 1); + if (memory == NULL) + { + errno = ENOMEM; + return 0; + } + t1 = memory; + t2 = memory + t1len + 1; + + /* Csae-fold the two argument strings. */ + if (MB_CUR_MAX > 1) + { + t1len = apply_towlower (s1, s1len, t1, t1len); + t2len = apply_towlower (s2, s2len, t2, t2len); + } + else + { + apply_tolower (s1, t1, s1len); + apply_tolower (s2, t2, s2len); + } + + /* Compare the two case-folded strings. */ + if (hard_LC_COLLATE) + cmp = memcoll (t1, t1len, t2, t2len); + else + { + cmp = memcmp2 (t1, t1len, t2, t2len); + errno = 0; + } + + { + int saved_errno = errno; + freea (memory); + errno = saved_errno; + } + + return cmp; +} |