summaryrefslogtreecommitdiffstats
path: root/lib/mbscasecmp.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/mbscasecmp.c')
-rw-r--r--lib/mbscasecmp.c102
1 files changed, 102 insertions, 0 deletions
diff --git a/lib/mbscasecmp.c b/lib/mbscasecmp.c
new file mode 100644
index 0000000..3a20cb7
--- /dev/null
+++ b/lib/mbscasecmp.c
@@ -0,0 +1,102 @@
+/* Case-insensitive string comparison function.
+ Copyright (C) 1998-1999, 2005-2023 Free Software Foundation, Inc.
+ Written by Bruno Haible <bruno@clisp.org>, 2005,
+ based on earlier glibc code.
+
+ This file 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 file 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 <https://www.gnu.org/licenses/>. */
+
+#include <config.h>
+
+/* Specification. */
+#include <string.h>
+
+#include <ctype.h>
+#include <limits.h>
+
+#include "mbuiterf.h"
+
+/* Compare the character strings S1 and S2, ignoring case, returning less than,
+ equal to or greater than zero if S1 is lexicographically less than, equal to
+ or greater than S2.
+ Note: This function may, in multibyte locales, return 0 for strings of
+ different lengths! */
+int
+mbscasecmp (const char *s1, const char *s2)
+{
+ if (s1 == s2)
+ return 0;
+
+ /* Be careful not to look at the entire extent of s1 or s2 until needed.
+ This is useful because when two strings differ, the difference is
+ most often already in the very few first characters. */
+ if (MB_CUR_MAX > 1)
+ {
+ mbuif_state_t state1;
+ const char *iter1;
+ mbuif_init (state1);
+ iter1 = s1;
+
+ mbuif_state_t state2;
+ const char *iter2;
+ mbuif_init (state2);
+ iter2 = s2;
+
+ while (mbuif_avail (state1, iter1) && mbuif_avail (state2, iter2))
+ {
+ mbchar_t cur1 = mbuif_next (state1, iter1);
+ mbchar_t cur2 = mbuif_next (state2, iter2);
+ int cmp = mb_casecmp (cur1, cur2);
+
+ if (cmp != 0)
+ return cmp;
+
+ iter1 += mb_len (cur1);
+ iter2 += mb_len (cur2);
+ }
+ if (mbuif_avail (state1, iter1))
+ /* s2 terminated before s1. */
+ return 1;
+ if (mbuif_avail (state2, iter2))
+ /* s1 terminated before s2. */
+ return -1;
+ return 0;
+ }
+ else
+ {
+ const unsigned char *p1 = (const unsigned char *) s1;
+ const unsigned char *p2 = (const unsigned char *) s2;
+ unsigned char c1, c2;
+
+ do
+ {
+ c1 = tolower (*p1);
+ c2 = tolower (*p2);
+
+ if (c1 == '\0')
+ break;
+
+ ++p1;
+ ++p2;
+ }
+ while (c1 == c2);
+
+ if (UCHAR_MAX <= INT_MAX)
+ return c1 - c2;
+ else
+ /* On machines where 'char' and 'int' are types of the same size, the
+ difference of two 'unsigned char' values - including the sign bit -
+ doesn't fit in an 'int'. */
+ return _GL_CMP (c1, c2);
+ }
+}