Most of the uses of strncasecmp are for the purpose of testing whether a string is prefix of another string. Using mbsncasecmp() is not comfortable for this case. I'm adding a new function mbspcasecmp() for this purpose. The 'p' stands for "prefix" or "pointer".
2007-02-14 Bruno Haible <[EMAIL PROTECTED]> New module mbspcasecmp. * modules/mbspcasecmp: New file. * lib/mbspcasecmp.c: New file. * lib/string_.h (strncasecmp): Change warning message. (mbspcasecmp): New declaration. * m4/mbspcasecmp.m4: New file. * m4/string_h.m4 (gl_STRING_MODULE_INDICATOR_DEFAULTS): Initialize GNULIB_MBSPCASECMP. * modules/string (string.h): Also substitute GNULIB_MBSPCASECMP. * MODULES.html.sh (Internationalization functions): Add mbspcasecmp. =========================== modules/mbspcasecmp ============================= Description: mbspcasecmp() function: case-insensitive string prefix comparison. Files: lib/mbspcasecmp.c m4/mbspcasecmp.m4 m4/mbrtowc.m4 Depends-on: mbuiter string configure.ac: gl_FUNC_MBSPCASECMP gl_STRING_MODULE_INDICATOR([mbspcasecmp]) Makefile.am: lib_SOURCES += mbspcasecmp.c Include: <string.h> License: LGPL Maintainer: Bruno Haible ============================ lib/mbspcasecmp.c ============================== /* Case-insensitive string comparison function. Copyright (C) 1998-1999, 2005-2007 Free Software Foundation, Inc. Written by Bruno Haible <[EMAIL PROTECTED]>, 2007. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, 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 General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include <config.h> /* Specification. */ #include <string.h> #include <ctype.h> #if HAVE_MBRTOWC # include "mbuiter.h" #endif #define TOLOWER(Ch) (isupper (Ch) ? tolower (Ch) : (Ch)) /* Compare the initial segment of the character string STRING consisting of at most mbslen (PREFIX) characters with the character string PREFIX, ignoring case, returning less than, equal to or greater than zero if this initial segment is lexicographically less than, equal to or greater than PREFIX. Note: This function may, in multibyte locales, return 0 if STRING is of smaller length than PREFIX! */ char * mbspcasecmp (const char *string, const char *prefix) { /* This is essentially the same as mbsncasecmp (string, prefix, mbslen (prefix)) just with small optimizations. */ if (string == prefix) return (char *) (string + strlen (string)); /* Be careful not to look at the entire extent of STRING or PREFIX until needed. This is useful because when two strings differ, the difference is most often already in the very few first characters. */ #if HAVE_MBRTOWC if (MB_CUR_MAX > 1) { mbui_iterator_t iter1; mbui_iterator_t iter2; mbui_init (iter1, string); mbui_init (iter2, prefix); while (mbui_avail (iter1) && mbui_avail (iter2)) { int cmp = mb_casecmp (mbui_cur (iter1), mbui_cur (iter2)); if (cmp != 0) return NULL; mbui_advance (iter1); mbui_advance (iter2); } if (!mbui_avail (iter2)) /* PREFIX equals STRING or is terminated before STRING. */ return (char *) mbui_cur_ptr (iter1); else /* STRING terminated before PREFIX. */ return NULL; } else #endif { const unsigned char *p1 = (const unsigned char *) string; const unsigned char *p2 = (const unsigned char *) prefix; unsigned char c1, c2; for (; ; p1++, p2++) { c1 = TOLOWER (*p1); c2 = TOLOWER (*p2); if (c2 == '\0' || c1 != c2) break; } if (c2 == '\0') /* PREFIX equals STRING or is terminated before STRING. */ return (char *) p1; else /* STRING terminated before PREFIX. */ return NULL; } } ============================ m4/mbspcasecmp.m4 ============================== # mbspcasecmp.m4 serial 1 dnl Copyright (C) 2007 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, dnl with or without modifications, as long as this notice is preserved. AC_DEFUN([gl_FUNC_MBSPCASECMP], [ gl_PREREQ_MBSPCASECMP ]) # Prerequisites of lib/mbspcasecmp.c. AC_DEFUN([gl_PREREQ_MBSPCASECMP], [ AC_REQUIRE([gl_FUNC_MBRTOWC]) : ]) ============================================================================= --- MODULES.html.sh 15 Feb 2007 02:59:33 -0000 1.193 +++ MODULES.html.sh 15 Feb 2007 03:01:28 -0000 @@ -2167,6 +2167,7 @@ func_module mbsstr func_module mbscasecmp func_module mbsncasecmp + func_module mbspcasecmp func_module mbscasestr func_module mbscspn func_module mbspbrk --- lib/string_.h 15 Feb 2007 02:59:33 -0000 1.23 +++ lib/string_.h 15 Feb 2007 03:01:29 -0000 @@ -152,7 +152,7 @@ as a sequence of bytes, not of characters. */ # undef strncasecmp # define strncasecmp(a,b,n) \ - (GL_LINK_WARNING ("strncasecmp cannot work correctly on character strings in multibyte locales - don't use it if you care about internationalization; use c_strncasecmp (from gnulib module c-strcase) if you want a locale independent function"), \ + (GL_LINK_WARNING ("strncasecmp cannot work correctly on character strings in multibyte locales - use mbsncasecmp or mbspcasecmp if you care about internationalization, or use c_strncasecmp (from gnulib module c-strcase) if you want a locale independent function"), \ strncasecmp (a, b, n)) #endif @@ -428,6 +428,19 @@ extern int mbsncasecmp (const char *s1, const char *s2, size_t n); #endif +#if @GNULIB_MBSPCASECMP@ +/* Compare the initial segment of the character string STRING consisting of + at most mbslen (PREFIX) characters with the character string PREFIX, + ignoring case, returning less than, equal to or greater than zero if this + initial segment is lexicographically less than, equal to or greater than + PREFIX. + Note: This function may, in multibyte locales, return 0 if STRING is of + smaller length than PREFIX! + Unlike strncasecmp(), this function works correctly in multibyte + locales. */ +extern char * mbspcasecmp (const char *string, const char *prefix); +#endif + #if @GNULIB_MBSCASESTR@ /* Find the first occurrence of the character string NEEDLE in the character string HAYSTACK, using case-insensitive comparison. --- m4/string_h.m4 15 Feb 2007 02:59:33 -0000 1.19 +++ m4/string_h.m4 15 Feb 2007 03:01:29 -0000 @@ -73,6 +73,7 @@ GNULIB_MBSSTR=0; AC_SUBST([GNULIB_MBSSTR]) GNULIB_MBSCASECMP=0; AC_SUBST([GNULIB_MBSCASECMP]) GNULIB_MBSNCASECMP=0; AC_SUBST([GNULIB_MBSNCASECMP]) + GNULIB_MBSPCASECMP=0; AC_SUBST([GNULIB_MBSPCASECMP]) GNULIB_MBSCASESTR=0; AC_SUBST([GNULIB_MBSCASESTR]) GNULIB_MBSCSPN=0; AC_SUBST([GNULIB_MBSCSPN]) GNULIB_MBSPBRK=0; AC_SUBST([GNULIB_MBSPBRK]) --- modules/string 15 Feb 2007 02:59:33 -0000 1.18 +++ modules/string 15 Feb 2007 03:01:29 -0000 @@ -27,6 +27,7 @@ -e 's|@''GNULIB_MBSSTR''@|$(GNULIB_MBSSTR)|g' \ -e 's|@''GNULIB_MBSCASECMP''@|$(GNULIB_MBSCASECMP)|g' \ -e 's|@''GNULIB_MBSNCASECMP''@|$(GNULIB_MBSNCASECMP)|g' \ + -e 's|@''GNULIB_MBSPCASECMP''@|$(GNULIB_MBSPCASECMP)|g' \ -e 's|@''GNULIB_MBSCASESTR''@|$(GNULIB_MBSCASESTR)|g' \ -e 's|@''GNULIB_MBSCSPN''@|$(GNULIB_MBSCSPN)|g' \ -e 's|@''GNULIB_MBSPBRK''@|$(GNULIB_MBSPBRK)|g' \