xref: /dflybsd-src/contrib/grep/lib/mbscasecmp.c (revision 91b9ed38d3db6a8a8ac5b66da1d43e6e331e259a)
195b7b453SJohn Marino /* Case-insensitive string comparison function.
2*09d4459fSDaniel Fojt    Copyright (C) 1998-1999, 2005-2020 Free Software Foundation, Inc.
395b7b453SJohn Marino    Written by Bruno Haible <bruno@clisp.org>, 2005,
495b7b453SJohn Marino    based on earlier glibc code.
595b7b453SJohn Marino 
695b7b453SJohn Marino    This program is free software: you can redistribute it and/or modify
795b7b453SJohn Marino    it under the terms of the GNU General Public License as published by
895b7b453SJohn Marino    the Free Software Foundation; either version 3 of the License, or
995b7b453SJohn Marino    (at your option) any later version.
1095b7b453SJohn Marino 
1195b7b453SJohn Marino    This program is distributed in the hope that it will be useful,
1295b7b453SJohn Marino    but WITHOUT ANY WARRANTY; without even the implied warranty of
1395b7b453SJohn Marino    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1495b7b453SJohn Marino    GNU General Public License for more details.
1595b7b453SJohn Marino 
1695b7b453SJohn Marino    You should have received a copy of the GNU General Public License
17*09d4459fSDaniel Fojt    along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
1895b7b453SJohn Marino 
1995b7b453SJohn Marino #include <config.h>
2095b7b453SJohn Marino 
2195b7b453SJohn Marino /* Specification.  */
2295b7b453SJohn Marino #include <string.h>
2395b7b453SJohn Marino 
2495b7b453SJohn Marino #include <ctype.h>
2595b7b453SJohn Marino #include <limits.h>
2695b7b453SJohn Marino 
2795b7b453SJohn Marino #include "mbuiter.h"
2895b7b453SJohn Marino 
2995b7b453SJohn Marino #define TOLOWER(Ch) (isupper (Ch) ? tolower (Ch) : (Ch))
3095b7b453SJohn Marino 
3195b7b453SJohn Marino /* Compare the character strings S1 and S2, ignoring case, returning less than,
3295b7b453SJohn Marino    equal to or greater than zero if S1 is lexicographically less than, equal to
3395b7b453SJohn Marino    or greater than S2.
3495b7b453SJohn Marino    Note: This function may, in multibyte locales, return 0 for strings of
3595b7b453SJohn Marino    different lengths!  */
3695b7b453SJohn Marino int
mbscasecmp(const char * s1,const char * s2)3795b7b453SJohn Marino mbscasecmp (const char *s1, const char *s2)
3895b7b453SJohn Marino {
3995b7b453SJohn Marino   if (s1 == s2)
4095b7b453SJohn Marino     return 0;
4195b7b453SJohn Marino 
4295b7b453SJohn Marino   /* Be careful not to look at the entire extent of s1 or s2 until needed.
4395b7b453SJohn Marino      This is useful because when two strings differ, the difference is
4495b7b453SJohn Marino      most often already in the very few first characters.  */
4595b7b453SJohn Marino   if (MB_CUR_MAX > 1)
4695b7b453SJohn Marino     {
4795b7b453SJohn Marino       mbui_iterator_t iter1;
4895b7b453SJohn Marino       mbui_iterator_t iter2;
4995b7b453SJohn Marino 
5095b7b453SJohn Marino       mbui_init (iter1, s1);
5195b7b453SJohn Marino       mbui_init (iter2, s2);
5295b7b453SJohn Marino 
5395b7b453SJohn Marino       while (mbui_avail (iter1) && mbui_avail (iter2))
5495b7b453SJohn Marino         {
5595b7b453SJohn Marino           int cmp = mb_casecmp (mbui_cur (iter1), mbui_cur (iter2));
5695b7b453SJohn Marino 
5795b7b453SJohn Marino           if (cmp != 0)
5895b7b453SJohn Marino             return cmp;
5995b7b453SJohn Marino 
6095b7b453SJohn Marino           mbui_advance (iter1);
6195b7b453SJohn Marino           mbui_advance (iter2);
6295b7b453SJohn Marino         }
6395b7b453SJohn Marino       if (mbui_avail (iter1))
6495b7b453SJohn Marino         /* s2 terminated before s1.  */
6595b7b453SJohn Marino         return 1;
6695b7b453SJohn Marino       if (mbui_avail (iter2))
6795b7b453SJohn Marino         /* s1 terminated before s2.  */
6895b7b453SJohn Marino         return -1;
6995b7b453SJohn Marino       return 0;
7095b7b453SJohn Marino     }
7195b7b453SJohn Marino   else
7295b7b453SJohn Marino     {
7395b7b453SJohn Marino       const unsigned char *p1 = (const unsigned char *) s1;
7495b7b453SJohn Marino       const unsigned char *p2 = (const unsigned char *) s2;
7595b7b453SJohn Marino       unsigned char c1, c2;
7695b7b453SJohn Marino 
7795b7b453SJohn Marino       do
7895b7b453SJohn Marino         {
7995b7b453SJohn Marino           c1 = TOLOWER (*p1);
8095b7b453SJohn Marino           c2 = TOLOWER (*p2);
8195b7b453SJohn Marino 
8295b7b453SJohn Marino           if (c1 == '\0')
8395b7b453SJohn Marino             break;
8495b7b453SJohn Marino 
8595b7b453SJohn Marino           ++p1;
8695b7b453SJohn Marino           ++p2;
8795b7b453SJohn Marino         }
8895b7b453SJohn Marino       while (c1 == c2);
8995b7b453SJohn Marino 
9095b7b453SJohn Marino       if (UCHAR_MAX <= INT_MAX)
9195b7b453SJohn Marino         return c1 - c2;
9295b7b453SJohn Marino       else
9395b7b453SJohn Marino         /* On machines where 'char' and 'int' are types of the same size, the
9495b7b453SJohn Marino            difference of two 'unsigned char' values - including the sign bit -
9595b7b453SJohn Marino            doesn't fit in an 'int'.  */
9695b7b453SJohn Marino         return (c1 > c2 ? 1 : c1 < c2 ? -1 : 0);
9795b7b453SJohn Marino     }
9895b7b453SJohn Marino }
99