GNU bug report logs - #11786
Use c_strcasecmp for portable ASCII case-insensitive comparison

Previous Next

Package: emacs;

Reported by: Paul Eggert <eggert <at> cs.ucla.edu>

Date: Tue, 26 Jun 2012 01:47:08 UTC

Severity: normal

Tags: patch

Done: Paul Eggert <eggert <at> cs.ucla.edu>

Bug is archived. No further changes may be made.

To add a comment to this bug, you must first unarchive it, by sending
a message to control AT debbugs.gnu.org, with unarchive 11786 in the body.
You can then email your comments to 11786 AT debbugs.gnu.org in the normal way.

Toggle the display of automated, internal messages from the tracker.

View this report as an mbox folder, status mbox, maintainer mbox


Report forwarded to bug-gnu-emacs <at> gnu.org:
bug#11786; Package emacs. (Tue, 26 Jun 2012 01:47:09 GMT) Full text and rfc822 format available.

Acknowledgement sent to Paul Eggert <eggert <at> cs.ucla.edu>:
New bug report received and forwarded. Copy sent to bug-gnu-emacs <at> gnu.org. (Tue, 26 Jun 2012 01:47:10 GMT) Full text and rfc822 format available.

Message #5 received at submit <at> debbugs.gnu.org (full text, mbox):

From: Paul Eggert <eggert <at> cs.ucla.edu>
To: bug-gnu-emacs <at> gnu.org
Subject: Use c_strcasecmp for portable ASCII case-insensitive comparison
Date: Mon, 25 Jun 2012 18:42:08 -0700
Tags: patch

Emacs currently use 'strcasecmp' and 'strncasecmp' for
case-insensitive comparison but these have problems in multibyte
locales.  In practice Emacs code really just wants a C-locale
version of these functions so I'm planning on installing the
following patch after some more testing.  I'm giving some
heads-up as this affects the Microsoft ports.

=== modified file 'ChangeLog'
--- ChangeLog	2012-06-26 01:05:39 +0000
+++ ChangeLog	2012-06-26 01:35:27 +0000
@@ -1,5 +1,14 @@
 2012-06-26  Paul Eggert  <eggert <at> cs.ucla.edu>
 
+	Use c_strcasecmp for portable ASCII case-insensitive comparison.
+	This is safer than strcasecmp, which has unspecified behavior
+	outside the POSIX locale and in practice sometimes does not work
+	in multibyte locales.  Similarly for c_strncasecmp and strncasecmp.
+	* configure.in (strcasecmp, strncasecmp): Remove checks.
+	* lib/c-ctype.c, lib/c-ctype.h, lib/c-strcase.h, lib/c-strcasecmp.c:
+	* lib/c-strncasecmp.c: New files, taken from gnulib.
+	* lib/gnulib.mk, m4/gnulib-comp.m4: Regenerate.
+
 	Clean out last vestiges of the old HAVE_CONFIG_H stuff.
 	* lib/makefile.w32-in (LOCAL_FLAGS): Remove -DHAVE_CONFIG_H.
 

=== modified file 'admin/ChangeLog'
--- admin/ChangeLog	2012-06-24 16:18:41 +0000
+++ admin/ChangeLog	2012-06-26 01:35:27 +0000
@@ -1,3 +1,8 @@
+2012-06-26  Paul Eggert  <eggert <at> cs.ucla.edu>
+
+	Use c_strcasecmp for portable ASCII case-insensitive comparison.
+	* merge-gnulib (GNULIB_MODULES): Add c-strcase.
+
 2012-06-24  Dmitry Antipov  <dmantipov <at> yandex.ru>
 
 	First Coccinelle semantic patch.

=== modified file 'admin/merge-gnulib'
--- admin/merge-gnulib	2012-06-22 21:17:42 +0000
+++ admin/merge-gnulib	2012-06-26 01:35:27 +0000
@@ -26,7 +26,7 @@
 GNULIB_URL=git://git.savannah.gnu.org/gnulib.git
 
 GNULIB_MODULES='
-  alloca-opt
+  alloca-opt c-strcase
   careadlinkat crypto/md5 crypto/sha1 crypto/sha256 crypto/sha512
   dtoastr dtotimespec dup2
   filemode getloadavg getopt-gnu gettime gettimeofday

=== modified file 'configure.in'
--- configure.in	2012-06-25 14:07:04 +0000
+++ configure.in	2012-06-26 01:35:27 +0000
@@ -2671,7 +2671,6 @@
 difftime posix_memalign \
 getpwent endpwent getgrent endgrent \
 touchlock \
-strcasecmp strncasecmp \
 cfmakeraw cfsetspeed copysign __executable_start)
 
 dnl Cannot use AC_CHECK_FUNCS

=== modified file 'lib-src/ChangeLog'
--- lib-src/ChangeLog	2012-06-26 01:05:39 +0000
+++ lib-src/ChangeLog	2012-06-26 01:35:27 +0000
@@ -1,5 +1,10 @@
 2012-06-26  Paul Eggert  <eggert <at> cs.ucla.edu>
 
+	Use c_strcasecmp for portable ASCII case-insensitive comparison.
+	* etags.c: Include c-strcase.h.
+	(etags_strcasecmp, etags_strncasecmp): Remove.
+	All uses replaced with c_strcasecmp and c_strncasecmp.
+
 	Clean out last vestiges of the old HAVE_CONFIG_H stuff.
 	* Makefile.in (BASE_CFLAGS):
 	* makefile.w32-in (LOCAL_FLAGS): Remove -DHAVE_CONFIG_H.

=== modified file 'lib-src/etags.c'
--- lib-src/etags.c	2012-06-26 01:05:39 +0000
+++ lib-src/etags.c	2012-06-26 01:35:27 +0000
@@ -144,6 +144,7 @@
 #include <errno.h>
 #include <sys/types.h>
 #include <sys/stat.h>
+#include <c-strcase.h>
 
 #include <assert.h>
 #ifdef NDEBUG
@@ -174,9 +175,9 @@
 #endif
 
 #define streq(s,t)	(assert ((s)!=NULL || (t)!=NULL), !strcmp (s, t))
-#define strcaseeq(s,t)	(assert ((s)!=NULL && (t)!=NULL), !etags_strcasecmp (s, t))
+#define strcaseeq(s,t)	(assert ((s)!=NULL && (t)!=NULL), !c_strcasecmp (s, t))
 #define strneq(s,t,n)	(assert ((s)!=NULL || (t)!=NULL), !strncmp (s, t, n))
-#define strncaseeq(s,t,n) (assert ((s)!=NULL && (t)!=NULL), !etags_strncasecmp (s, t, n))
+#define strncaseeq(s,t,n) (assert ((s)!=NULL && (t)!=NULL), !c_strncasecmp (s, t, n))
 
 #define CHARS 256		/* 2^sizeof(char) */
 #define CHAR(x)		((unsigned int)(x) & (CHARS - 1))
@@ -375,16 +376,6 @@
 static char *savestr (const char *);
 static char *etags_strchr (const char *, int);
 static char *etags_strrchr (const char *, int);
-#ifdef HAVE_STRCASECMP
-#define etags_strcasecmp(x,y) strcasecmp ((x), (y))
-#else
-static int etags_strcasecmp (const char *, const char *);
-#endif
-#ifdef HAVE_STRNCASECMP
-#define etags_strncasecmp(x,y,z) strncasecmp ((x), (y), (z))
-#else
-static int etags_strncasecmp (const char *, const char *, int);
-#endif
 static char *etags_getcwd (void);
 static char *relative_filename (char *, char *);
 static char *absolute_filename (char *, char *);
@@ -6314,52 +6305,6 @@
   return NULL;
 }
 
-#ifndef HAVE_STRCASECMP
-/*
- * Compare two strings, ignoring case for alphabetic characters.
- *
- * Same as BSD's strcasecmp, included for portability.
- */
-static int
-etags_strcasecmp (register const char *s1, register const char *s2)
-{
-  while (*s1 != '\0'
-	 && (ISALPHA (*s1) && ISALPHA (*s2)
-	     ? lowcase (*s1) == lowcase (*s2)
-	     : *s1 == *s2))
-    s1++, s2++;
-
-  return (ISALPHA (*s1) && ISALPHA (*s2)
-	  ? lowcase (*s1) - lowcase (*s2)
-	  : *s1 - *s2);
-}
-#endif /* HAVE_STRCASECMP */
-
-#ifndef HAVE_STRNCASECMP
-/*
- * Compare two strings, ignoring case for alphabetic characters.
- * Stop after a given number of characters
- *
- * Same as BSD's strncasecmp, included for portability.
- */
-static int
-etags_strncasecmp (register const char *s1, register const char *s2, register int n)
-{
-  while (*s1 != '\0' && n-- > 0
-	 && (ISALPHA (*s1) && ISALPHA (*s2)
-	     ? lowcase (*s1) == lowcase (*s2)
-	     : *s1 == *s2))
-    s1++, s2++;
-
-  if (n < 0)
-    return 0;
-  else
-    return (ISALPHA (*s1) && ISALPHA (*s2)
-	    ? lowcase (*s1) - lowcase (*s2)
-	    : *s1 - *s2);
-}
-#endif /* HAVE_STRCASECMP */
-
 /* Skip spaces (end of string is not space), return new pointer. */
 static char *
 skip_spaces (char *cp)

=== added file 'lib/c-ctype.c'
--- lib/c-ctype.c	1970-01-01 00:00:00 +0000
+++ lib/c-ctype.c	2012-06-26 01:35:27 +0000
@@ -0,0 +1,395 @@
+/* Character handling in C locale.
+
+   Copyright 2000-2003, 2006, 2009-2012 Free Software Foundation, Inc.
+
+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 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 General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, see <http://www.gnu.org/licenses/>.  */
+
+#include <config.h>
+
+/* Specification.  */
+#define NO_C_CTYPE_MACROS
+#include "c-ctype.h"
+
+/* The function isascii is not locale dependent. Its use in EBCDIC is
+   questionable. */
+bool
+c_isascii (int c)
+{
+  return (c >= 0x00 && c <= 0x7f);
+}
+
+bool
+c_isalnum (int c)
+{
+#if C_CTYPE_CONSECUTIVE_DIGITS \
+    && C_CTYPE_CONSECUTIVE_UPPERCASE && C_CTYPE_CONSECUTIVE_LOWERCASE
+#if C_CTYPE_ASCII
+  return ((c >= '0' && c <= '9')
+          || ((c & ~0x20) >= 'A' && (c & ~0x20) <= 'Z'));
+#else
+  return ((c >= '0' && c <= '9')
+          || (c >= 'A' && c <= 'Z')
+          || (c >= 'a' && c <= 'z'));
+#endif
+#else
+  switch (c)
+    {
+    case '0': case '1': case '2': case '3': case '4': case '5':
+    case '6': case '7': case '8': case '9':
+    case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
+    case 'G': case 'H': case 'I': case 'J': case 'K': case 'L':
+    case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R':
+    case 'S': case 'T': case 'U': case 'V': case 'W': case 'X':
+    case 'Y': case 'Z':
+    case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
+    case 'g': case 'h': case 'i': case 'j': case 'k': case 'l':
+    case 'm': case 'n': case 'o': case 'p': case 'q': case 'r':
+    case 's': case 't': case 'u': case 'v': case 'w': case 'x':
+    case 'y': case 'z':
+      return 1;
+    default:
+      return 0;
+    }
+#endif
+}
+
+bool
+c_isalpha (int c)
+{
+#if C_CTYPE_CONSECUTIVE_UPPERCASE && C_CTYPE_CONSECUTIVE_LOWERCASE
+#if C_CTYPE_ASCII
+  return ((c & ~0x20) >= 'A' && (c & ~0x20) <= 'Z');
+#else
+  return ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z'));
+#endif
+#else
+  switch (c)
+    {
+    case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
+    case 'G': case 'H': case 'I': case 'J': case 'K': case 'L':
+    case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R':
+    case 'S': case 'T': case 'U': case 'V': case 'W': case 'X':
+    case 'Y': case 'Z':
+    case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
+    case 'g': case 'h': case 'i': case 'j': case 'k': case 'l':
+    case 'm': case 'n': case 'o': case 'p': case 'q': case 'r':
+    case 's': case 't': case 'u': case 'v': case 'w': case 'x':
+    case 'y': case 'z':
+      return 1;
+    default:
+      return 0;
+    }
+#endif
+}
+
+bool
+c_isblank (int c)
+{
+  return (c == ' ' || c == '\t');
+}
+
+bool
+c_iscntrl (int c)
+{
+#if C_CTYPE_ASCII
+  return ((c & ~0x1f) == 0 || c == 0x7f);
+#else
+  switch (c)
+    {
+    case ' ': case '!': case '"': case '#': case '$': case '%':
+    case '&': case '\'': case '(': case ')': case '*': case '+':
+    case ',': case '-': case '.': case '/':
+    case '0': case '1': case '2': case '3': case '4': case '5':
+    case '6': case '7': case '8': case '9':
+    case ':': case ';': case '<': case '=': case '>': case '?':
+    case '@':
+    case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
+    case 'G': case 'H': case 'I': case 'J': case 'K': case 'L':
+    case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R':
+    case 'S': case 'T': case 'U': case 'V': case 'W': case 'X':
+    case 'Y': case 'Z':
+    case '[': case '\\': case ']': case '^': case '_': case '`':
+    case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
+    case 'g': case 'h': case 'i': case 'j': case 'k': case 'l':
+    case 'm': case 'n': case 'o': case 'p': case 'q': case 'r':
+    case 's': case 't': case 'u': case 'v': case 'w': case 'x':
+    case 'y': case 'z':
+    case '{': case '|': case '}': case '~':
+      return 0;
+    default:
+      return 1;
+    }
+#endif
+}
+
+bool
+c_isdigit (int c)
+{
+#if C_CTYPE_CONSECUTIVE_DIGITS
+  return (c >= '0' && c <= '9');
+#else
+  switch (c)
+    {
+    case '0': case '1': case '2': case '3': case '4': case '5':
+    case '6': case '7': case '8': case '9':
+      return 1;
+    default:
+      return 0;
+    }
+#endif
+}
+
+bool
+c_islower (int c)
+{
+#if C_CTYPE_CONSECUTIVE_LOWERCASE
+  return (c >= 'a' && c <= 'z');
+#else
+  switch (c)
+    {
+    case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
+    case 'g': case 'h': case 'i': case 'j': case 'k': case 'l':
+    case 'm': case 'n': case 'o': case 'p': case 'q': case 'r':
+    case 's': case 't': case 'u': case 'v': case 'w': case 'x':
+    case 'y': case 'z':
+      return 1;
+    default:
+      return 0;
+    }
+#endif
+}
+
+bool
+c_isgraph (int c)
+{
+#if C_CTYPE_ASCII
+  return (c >= '!' && c <= '~');
+#else
+  switch (c)
+    {
+    case '!': case '"': case '#': case '$': case '%': case '&':
+    case '\'': case '(': case ')': case '*': case '+': case ',':
+    case '-': case '.': case '/':
+    case '0': case '1': case '2': case '3': case '4': case '5':
+    case '6': case '7': case '8': case '9':
+    case ':': case ';': case '<': case '=': case '>': case '?':
+    case '@':
+    case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
+    case 'G': case 'H': case 'I': case 'J': case 'K': case 'L':
+    case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R':
+    case 'S': case 'T': case 'U': case 'V': case 'W': case 'X':
+    case 'Y': case 'Z':
+    case '[': case '\\': case ']': case '^': case '_': case '`':
+    case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
+    case 'g': case 'h': case 'i': case 'j': case 'k': case 'l':
+    case 'm': case 'n': case 'o': case 'p': case 'q': case 'r':
+    case 's': case 't': case 'u': case 'v': case 'w': case 'x':
+    case 'y': case 'z':
+    case '{': case '|': case '}': case '~':
+      return 1;
+    default:
+      return 0;
+    }
+#endif
+}
+
+bool
+c_isprint (int c)
+{
+#if C_CTYPE_ASCII
+  return (c >= ' ' && c <= '~');
+#else
+  switch (c)
+    {
+    case ' ': case '!': case '"': case '#': case '$': case '%':
+    case '&': case '\'': case '(': case ')': case '*': case '+':
+    case ',': case '-': case '.': case '/':
+    case '0': case '1': case '2': case '3': case '4': case '5':
+    case '6': case '7': case '8': case '9':
+    case ':': case ';': case '<': case '=': case '>': case '?':
+    case '@':
+    case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
+    case 'G': case 'H': case 'I': case 'J': case 'K': case 'L':
+    case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R':
+    case 'S': case 'T': case 'U': case 'V': case 'W': case 'X':
+    case 'Y': case 'Z':
+    case '[': case '\\': case ']': case '^': case '_': case '`':
+    case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
+    case 'g': case 'h': case 'i': case 'j': case 'k': case 'l':
+    case 'm': case 'n': case 'o': case 'p': case 'q': case 'r':
+    case 's': case 't': case 'u': case 'v': case 'w': case 'x':
+    case 'y': case 'z':
+    case '{': case '|': case '}': case '~':
+      return 1;
+    default:
+      return 0;
+    }
+#endif
+}
+
+bool
+c_ispunct (int c)
+{
+#if C_CTYPE_ASCII
+  return ((c >= '!' && c <= '~')
+          && !((c >= '0' && c <= '9')
+               || ((c & ~0x20) >= 'A' && (c & ~0x20) <= 'Z')));
+#else
+  switch (c)
+    {
+    case '!': case '"': case '#': case '$': case '%': case '&':
+    case '\'': case '(': case ')': case '*': case '+': case ',':
+    case '-': case '.': case '/':
+    case ':': case ';': case '<': case '=': case '>': case '?':
+    case '@':
+    case '[': case '\\': case ']': case '^': case '_': case '`':
+    case '{': case '|': case '}': case '~':
+      return 1;
+    default:
+      return 0;
+    }
+#endif
+}
+
+bool
+c_isspace (int c)
+{
+  return (c == ' ' || c == '\t'
+          || c == '\n' || c == '\v' || c == '\f' || c == '\r');
+}
+
+bool
+c_isupper (int c)
+{
+#if C_CTYPE_CONSECUTIVE_UPPERCASE
+  return (c >= 'A' && c <= 'Z');
+#else
+  switch (c)
+    {
+    case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
+    case 'G': case 'H': case 'I': case 'J': case 'K': case 'L':
+    case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R':
+    case 'S': case 'T': case 'U': case 'V': case 'W': case 'X':
+    case 'Y': case 'Z':
+      return 1;
+    default:
+      return 0;
+    }
+#endif
+}
+
+bool
+c_isxdigit (int c)
+{
+#if C_CTYPE_CONSECUTIVE_DIGITS \
+    && C_CTYPE_CONSECUTIVE_UPPERCASE && C_CTYPE_CONSECUTIVE_LOWERCASE
+#if C_CTYPE_ASCII
+  return ((c >= '0' && c <= '9')
+          || ((c & ~0x20) >= 'A' && (c & ~0x20) <= 'F'));
+#else
+  return ((c >= '0' && c <= '9')
+          || (c >= 'A' && c <= 'F')
+          || (c >= 'a' && c <= 'f'));
+#endif
+#else
+  switch (c)
+    {
+    case '0': case '1': case '2': case '3': case '4': case '5':
+    case '6': case '7': case '8': case '9':
+    case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
+    case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
+      return 1;
+    default:
+      return 0;
+    }
+#endif
+}
+
+int
+c_tolower (int c)
+{
+#if C_CTYPE_CONSECUTIVE_UPPERCASE && C_CTYPE_CONSECUTIVE_LOWERCASE
+  return (c >= 'A' && c <= 'Z' ? c - 'A' + 'a' : c);
+#else
+  switch (c)
+    {
+    case 'A': return 'a';
+    case 'B': return 'b';
+    case 'C': return 'c';
+    case 'D': return 'd';
+    case 'E': return 'e';
+    case 'F': return 'f';
+    case 'G': return 'g';
+    case 'H': return 'h';
+    case 'I': return 'i';
+    case 'J': return 'j';
+    case 'K': return 'k';
+    case 'L': return 'l';
+    case 'M': return 'm';
+    case 'N': return 'n';
+    case 'O': return 'o';
+    case 'P': return 'p';
+    case 'Q': return 'q';
+    case 'R': return 'r';
+    case 'S': return 's';
+    case 'T': return 't';
+    case 'U': return 'u';
+    case 'V': return 'v';
+    case 'W': return 'w';
+    case 'X': return 'x';
+    case 'Y': return 'y';
+    case 'Z': return 'z';
+    default: return c;
+    }
+#endif
+}
+
+int
+c_toupper (int c)
+{
+#if C_CTYPE_CONSECUTIVE_UPPERCASE && C_CTYPE_CONSECUTIVE_LOWERCASE
+  return (c >= 'a' && c <= 'z' ? c - 'a' + 'A' : c);
+#else
+  switch (c)
+    {
+    case 'a': return 'A';
+    case 'b': return 'B';
+    case 'c': return 'C';
+    case 'd': return 'D';
+    case 'e': return 'E';
+    case 'f': return 'F';
+    case 'g': return 'G';
+    case 'h': return 'H';
+    case 'i': return 'I';
+    case 'j': return 'J';
+    case 'k': return 'K';
+    case 'l': return 'L';
+    case 'm': return 'M';
+    case 'n': return 'N';
+    case 'o': return 'O';
+    case 'p': return 'P';
+    case 'q': return 'Q';
+    case 'r': return 'R';
+    case 's': return 'S';
+    case 't': return 'T';
+    case 'u': return 'U';
+    case 'v': return 'V';
+    case 'w': return 'W';
+    case 'x': return 'X';
+    case 'y': return 'Y';
+    case 'z': return 'Z';
+    default: return c;
+    }
+#endif
+}

=== added file 'lib/c-ctype.h'
--- lib/c-ctype.h	1970-01-01 00:00:00 +0000
+++ lib/c-ctype.h	2012-06-26 01:35:27 +0000
@@ -0,0 +1,294 @@
+/* Character handling in C locale.
+
+   These functions work like the corresponding functions in <ctype.h>,
+   except that they have the C (POSIX) locale hardwired, whereas the
+   <ctype.h> functions' behaviour depends on the current locale set via
+   setlocale.
+
+   Copyright (C) 2000-2003, 2006, 2008-2012 Free Software Foundation, Inc.
+
+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 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 General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, see <http://www.gnu.org/licenses/>.  */
+
+#ifndef C_CTYPE_H
+#define C_CTYPE_H
+
+#include <stdbool.h>
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/* The functions defined in this file assume the "C" locale and a character
+   set without diacritics (ASCII-US or EBCDIC-US or something like that).
+   Even if the "C" locale on a particular system is an extension of the ASCII
+   character set (like on BeOS, where it is UTF-8, or on AmigaOS, where it
+   is ISO-8859-1), the functions in this file recognize only the ASCII
+   characters.  */
+
+
+/* Check whether the ASCII optimizations apply. */
+
+/* ANSI C89 (and ISO C99 5.2.1.3 too) already guarantees that
+   '0', '1', ..., '9' have consecutive integer values.  */
+#define C_CTYPE_CONSECUTIVE_DIGITS 1
+
+#if ('A' <= 'Z') \
+    && ('A' + 1 == 'B') && ('B' + 1 == 'C') && ('C' + 1 == 'D') \
+    && ('D' + 1 == 'E') && ('E' + 1 == 'F') && ('F' + 1 == 'G') \
+    && ('G' + 1 == 'H') && ('H' + 1 == 'I') && ('I' + 1 == 'J') \
+    && ('J' + 1 == 'K') && ('K' + 1 == 'L') && ('L' + 1 == 'M') \
+    && ('M' + 1 == 'N') && ('N' + 1 == 'O') && ('O' + 1 == 'P') \
+    && ('P' + 1 == 'Q') && ('Q' + 1 == 'R') && ('R' + 1 == 'S') \
+    && ('S' + 1 == 'T') && ('T' + 1 == 'U') && ('U' + 1 == 'V') \
+    && ('V' + 1 == 'W') && ('W' + 1 == 'X') && ('X' + 1 == 'Y') \
+    && ('Y' + 1 == 'Z')
+#define C_CTYPE_CONSECUTIVE_UPPERCASE 1
+#endif
+
+#if ('a' <= 'z') \
+    && ('a' + 1 == 'b') && ('b' + 1 == 'c') && ('c' + 1 == 'd') \
+    && ('d' + 1 == 'e') && ('e' + 1 == 'f') && ('f' + 1 == 'g') \
+    && ('g' + 1 == 'h') && ('h' + 1 == 'i') && ('i' + 1 == 'j') \
+    && ('j' + 1 == 'k') && ('k' + 1 == 'l') && ('l' + 1 == 'm') \
+    && ('m' + 1 == 'n') && ('n' + 1 == 'o') && ('o' + 1 == 'p') \
+    && ('p' + 1 == 'q') && ('q' + 1 == 'r') && ('r' + 1 == 's') \
+    && ('s' + 1 == 't') && ('t' + 1 == 'u') && ('u' + 1 == 'v') \
+    && ('v' + 1 == 'w') && ('w' + 1 == 'x') && ('x' + 1 == 'y') \
+    && ('y' + 1 == 'z')
+#define C_CTYPE_CONSECUTIVE_LOWERCASE 1
+#endif
+
+#if (' ' == 32) && ('!' == 33) && ('"' == 34) && ('#' == 35) \
+    && ('%' == 37) && ('&' == 38) && ('\'' == 39) && ('(' == 40) \
+    && (')' == 41) && ('*' == 42) && ('+' == 43) && (',' == 44) \
+    && ('-' == 45) && ('.' == 46) && ('/' == 47) && ('0' == 48) \
+    && ('1' == 49) && ('2' == 50) && ('3' == 51) && ('4' == 52) \
+    && ('5' == 53) && ('6' == 54) && ('7' == 55) && ('8' == 56) \
+    && ('9' == 57) && (':' == 58) && (';' == 59) && ('<' == 60) \
+    && ('=' == 61) && ('>' == 62) && ('?' == 63) && ('A' == 65) \
+    && ('B' == 66) && ('C' == 67) && ('D' == 68) && ('E' == 69) \
+    && ('F' == 70) && ('G' == 71) && ('H' == 72) && ('I' == 73) \
+    && ('J' == 74) && ('K' == 75) && ('L' == 76) && ('M' == 77) \
+    && ('N' == 78) && ('O' == 79) && ('P' == 80) && ('Q' == 81) \
+    && ('R' == 82) && ('S' == 83) && ('T' == 84) && ('U' == 85) \
+    && ('V' == 86) && ('W' == 87) && ('X' == 88) && ('Y' == 89) \
+    && ('Z' == 90) && ('[' == 91) && ('\\' == 92) && (']' == 93) \
+    && ('^' == 94) && ('_' == 95) && ('a' == 97) && ('b' == 98) \
+    && ('c' == 99) && ('d' == 100) && ('e' == 101) && ('f' == 102) \
+    && ('g' == 103) && ('h' == 104) && ('i' == 105) && ('j' == 106) \
+    && ('k' == 107) && ('l' == 108) && ('m' == 109) && ('n' == 110) \
+    && ('o' == 111) && ('p' == 112) && ('q' == 113) && ('r' == 114) \
+    && ('s' == 115) && ('t' == 116) && ('u' == 117) && ('v' == 118) \
+    && ('w' == 119) && ('x' == 120) && ('y' == 121) && ('z' == 122) \
+    && ('{' == 123) && ('|' == 124) && ('}' == 125) && ('~' == 126)
+/* The character set is ASCII or one of its variants or extensions, not EBCDIC.
+   Testing the value of '\n' and '\r' is not relevant.  */
+#define C_CTYPE_ASCII 1
+#endif
+
+
+/* Function declarations. */
+
+/* Unlike the functions in <ctype.h>, which require an argument in the range
+   of the 'unsigned char' type, the functions here operate on values that are
+   in the 'unsigned char' range or in the 'char' range.  In other words,
+   when you have a 'char' value, you need to cast it before using it as
+   argument to a <ctype.h> function:
+
+         const char *s = ...;
+         if (isalpha ((unsigned char) *s)) ...
+
+   but you don't need to cast it for the functions defined in this file:
+
+         const char *s = ...;
+         if (c_isalpha (*s)) ...
+ */
+
+extern bool c_isascii (int c) _GL_ATTRIBUTE_CONST; /* not locale dependent */
+
+extern bool c_isalnum (int c) _GL_ATTRIBUTE_CONST;
+extern bool c_isalpha (int c) _GL_ATTRIBUTE_CONST;
+extern bool c_isblank (int c) _GL_ATTRIBUTE_CONST;
+extern bool c_iscntrl (int c) _GL_ATTRIBUTE_CONST;
+extern bool c_isdigit (int c) _GL_ATTRIBUTE_CONST;
+extern bool c_islower (int c) _GL_ATTRIBUTE_CONST;
+extern bool c_isgraph (int c) _GL_ATTRIBUTE_CONST;
+extern bool c_isprint (int c) _GL_ATTRIBUTE_CONST;
+extern bool c_ispunct (int c) _GL_ATTRIBUTE_CONST;
+extern bool c_isspace (int c) _GL_ATTRIBUTE_CONST;
+extern bool c_isupper (int c) _GL_ATTRIBUTE_CONST;
+extern bool c_isxdigit (int c) _GL_ATTRIBUTE_CONST;
+
+extern int c_tolower (int c) _GL_ATTRIBUTE_CONST;
+extern int c_toupper (int c) _GL_ATTRIBUTE_CONST;
+
+
+#if defined __GNUC__ && defined __OPTIMIZE__ && !defined __OPTIMIZE_SIZE__ && !defined NO_C_CTYPE_MACROS
+
+/* ASCII optimizations. */
+
+#undef c_isascii
+#define c_isascii(c) \
+  ({ int __c = (c); \
+     (__c >= 0x00 && __c <= 0x7f); \
+   })
+
+#if C_CTYPE_CONSECUTIVE_DIGITS \
+    && C_CTYPE_CONSECUTIVE_UPPERCASE && C_CTYPE_CONSECUTIVE_LOWERCASE
+#if C_CTYPE_ASCII
+#undef c_isalnum
+#define c_isalnum(c) \
+  ({ int __c = (c); \
+     ((__c >= '0' && __c <= '9') \
+      || ((__c & ~0x20) >= 'A' && (__c & ~0x20) <= 'Z')); \
+   })
+#else
+#undef c_isalnum
+#define c_isalnum(c) \
+  ({ int __c = (c); \
+     ((__c >= '0' && __c <= '9') \
+      || (__c >= 'A' && __c <= 'Z') \
+      || (__c >= 'a' && __c <= 'z')); \
+   })
+#endif
+#endif
+
+#if C_CTYPE_CONSECUTIVE_UPPERCASE && C_CTYPE_CONSECUTIVE_LOWERCASE
+#if C_CTYPE_ASCII
+#undef c_isalpha
+#define c_isalpha(c) \
+  ({ int __c = (c); \
+     ((__c & ~0x20) >= 'A' && (__c & ~0x20) <= 'Z'); \
+   })
+#else
+#undef c_isalpha
+#define c_isalpha(c) \
+  ({ int __c = (c); \
+     ((__c >= 'A' && __c <= 'Z') || (__c >= 'a' && __c <= 'z')); \
+   })
+#endif
+#endif
+
+#undef c_isblank
+#define c_isblank(c) \
+  ({ int __c = (c); \
+     (__c == ' ' || __c == '\t'); \
+   })
+
+#if C_CTYPE_ASCII
+#undef c_iscntrl
+#define c_iscntrl(c) \
+  ({ int __c = (c); \
+     ((__c & ~0x1f) == 0 || __c == 0x7f); \
+   })
+#endif
+
+#if C_CTYPE_CONSECUTIVE_DIGITS
+#undef c_isdigit
+#define c_isdigit(c) \
+  ({ int __c = (c); \
+     (__c >= '0' && __c <= '9'); \
+   })
+#endif
+
+#if C_CTYPE_CONSECUTIVE_LOWERCASE
+#undef c_islower
+#define c_islower(c) \
+  ({ int __c = (c); \
+     (__c >= 'a' && __c <= 'z'); \
+   })
+#endif
+
+#if C_CTYPE_ASCII
+#undef c_isgraph
+#define c_isgraph(c) \
+  ({ int __c = (c); \
+     (__c >= '!' && __c <= '~'); \
+   })
+#endif
+
+#if C_CTYPE_ASCII
+#undef c_isprint
+#define c_isprint(c) \
+  ({ int __c = (c); \
+     (__c >= ' ' && __c <= '~'); \
+   })
+#endif
+
+#if C_CTYPE_ASCII
+#undef c_ispunct
+#define c_ispunct(c) \
+  ({ int _c = (c); \
+     (c_isgraph (_c) && ! c_isalnum (_c)); \
+   })
+#endif
+
+#undef c_isspace
+#define c_isspace(c) \
+  ({ int __c = (c); \
+     (__c == ' ' || __c == '\t' \
+      || __c == '\n' || __c == '\v' || __c == '\f' || __c == '\r'); \
+   })
+
+#if C_CTYPE_CONSECUTIVE_UPPERCASE
+#undef c_isupper
+#define c_isupper(c) \
+  ({ int __c = (c); \
+     (__c >= 'A' && __c <= 'Z'); \
+   })
+#endif
+
+#if C_CTYPE_CONSECUTIVE_DIGITS \
+    && C_CTYPE_CONSECUTIVE_UPPERCASE && C_CTYPE_CONSECUTIVE_LOWERCASE
+#if C_CTYPE_ASCII
+#undef c_isxdigit
+#define c_isxdigit(c) \
+  ({ int __c = (c); \
+     ((__c >= '0' && __c <= '9') \
+      || ((__c & ~0x20) >= 'A' && (__c & ~0x20) <= 'F')); \
+   })
+#else
+#undef c_isxdigit
+#define c_isxdigit(c) \
+  ({ int __c = (c); \
+     ((__c >= '0' && __c <= '9') \
+      || (__c >= 'A' && __c <= 'F') \
+      || (__c >= 'a' && __c <= 'f')); \
+   })
+#endif
+#endif
+
+#if C_CTYPE_CONSECUTIVE_UPPERCASE && C_CTYPE_CONSECUTIVE_LOWERCASE
+#undef c_tolower
+#define c_tolower(c) \
+  ({ int __c = (c); \
+     (__c >= 'A' && __c <= 'Z' ? __c - 'A' + 'a' : __c); \
+   })
+#undef c_toupper
+#define c_toupper(c) \
+  ({ int __c = (c); \
+     (__c >= 'a' && __c <= 'z' ? __c - 'a' + 'A' : __c); \
+   })
+#endif
+
+#endif /* optimizing for speed */
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* C_CTYPE_H */

=== added file 'lib/c-strcase.h'
--- lib/c-strcase.h	1970-01-01 00:00:00 +0000
+++ lib/c-strcase.h	2012-06-26 01:35:27 +0000
@@ -0,0 +1,56 @@
+/* Case-insensitive string comparison functions in C locale.
+   Copyright (C) 1995-1996, 2001, 2003, 2005, 2009-2012 Free Software
+   Foundation, Inc.
+
+   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 3, 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, see <http://www.gnu.org/licenses/>.  */
+
+#ifndef C_STRCASE_H
+#define C_STRCASE_H
+
+#include <stddef.h>
+
+
+/* The functions defined in this file assume the "C" locale and a character
+   set without diacritics (ASCII-US or EBCDIC-US or something like that).
+   Even if the "C" locale on a particular system is an extension of the ASCII
+   character set (like on BeOS, where it is UTF-8, or on AmigaOS, where it
+   is ISO-8859-1), the functions in this file recognize only the ASCII
+   characters.  More precisely, one of the string arguments must be an ASCII
+   string; the other one can also contain non-ASCII characters (but then
+   the comparison result will be nonzero).  */
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/* Compare 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.  */
+extern int c_strcasecmp (const char *s1, const char *s2) _GL_ATTRIBUTE_PURE;
+
+/* Compare no more than N characters of 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.  */
+extern int c_strncasecmp (const char *s1, const char *s2, size_t n)
+  _GL_ATTRIBUTE_PURE;
+
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif /* C_STRCASE_H */

=== added file 'lib/c-strcasecmp.c'
--- lib/c-strcasecmp.c	1970-01-01 00:00:00 +0000
+++ lib/c-strcasecmp.c	2012-06-26 01:35:27 +0000
@@ -0,0 +1,56 @@
+/* c-strcasecmp.c -- case insensitive string comparator in C locale
+   Copyright (C) 1998-1999, 2005-2006, 2009-2012 Free Software Foundation, Inc.
+
+   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 3, 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, see <http://www.gnu.org/licenses/>.  */
+
+#include <config.h>
+
+/* Specification.  */
+#include "c-strcase.h"
+
+#include <limits.h>
+
+#include "c-ctype.h"
+
+int
+c_strcasecmp (const char *s1, const char *s2)
+{
+  register const unsigned char *p1 = (const unsigned char *) s1;
+  register const unsigned char *p2 = (const unsigned char *) s2;
+  unsigned char c1, c2;
+
+  if (p1 == p2)
+    return 0;
+
+  do
+    {
+      c1 = c_tolower (*p1);
+      c2 = c_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 (c1 > c2 ? 1 : c1 < c2 ? -1 : 0);
+}

=== added file 'lib/c-strncasecmp.c'
--- lib/c-strncasecmp.c	1970-01-01 00:00:00 +0000
+++ lib/c-strncasecmp.c	2012-06-26 01:35:27 +0000
@@ -0,0 +1,56 @@
+/* c-strncasecmp.c -- case insensitive string comparator in C locale
+   Copyright (C) 1998-1999, 2005-2006, 2009-2012 Free Software Foundation, Inc.
+
+   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 3, 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, see <http://www.gnu.org/licenses/>.  */
+
+#include <config.h>
+
+/* Specification.  */
+#include "c-strcase.h"
+
+#include <limits.h>
+
+#include "c-ctype.h"
+
+int
+c_strncasecmp (const char *s1, const char *s2, size_t n)
+{
+  register const unsigned char *p1 = (const unsigned char *) s1;
+  register const unsigned char *p2 = (const unsigned char *) s2;
+  unsigned char c1, c2;
+
+  if (p1 == p2 || n == 0)
+    return 0;
+
+  do
+    {
+      c1 = c_tolower (*p1);
+      c2 = c_tolower (*p2);
+
+      if (--n == 0 || 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 (c1 > c2 ? 1 : c1 < c2 ? -1 : 0);
+}

=== modified file 'lib/gnulib.mk'
--- lib/gnulib.mk	2012-06-22 21:17:42 +0000
+++ lib/gnulib.mk	2012-06-26 01:35:27 +0000
@@ -21,7 +21,7 @@
 # the same distribution terms as the rest of that program.
 #
 # Generated by gnulib-tool.
-# Reproduce by: gnulib-tool --import --dir=. --lib=libgnu --source-base=lib --m4-base=m4 --doc-base=doc --tests-base=tests --aux-dir=build-aux --avoid=errno --avoid=fcntl --avoid=fcntl-h --avoid=fstat --avoid=msvc-inval --avoid=msvc-nothrow --avoid=raise --avoid=select --avoid=sigprocmask --avoid=sys_types --avoid=threadlib --makefile-name=gnulib.mk --conditional-dependencies --no-libtool --macro-prefix=gl --no-vc-files alloca-opt careadlinkat crypto/md5 crypto/sha1 crypto/sha256 crypto/sha512 dtoastr dtotimespec dup2 filemode getloadavg getopt-gnu gettime gettimeofday ignore-value intprops largefile lstat manywarnings mktime pselect pthread_sigmask readlink socklen stat-time stdarg stdio strftime strtoimax strtoumax symlink sys_stat sys_time time timespec-add timespec-sub utimens warnings
+# Reproduce by: gnulib-tool --import --dir=. --lib=libgnu --source-base=lib --m4-base=m4 --doc-base=doc --tests-base=tests --aux-dir=build-aux --avoid=errno --avoid=fcntl --avoid=fcntl-h --avoid=fstat --avoid=msvc-inval --avoid=msvc-nothrow --avoid=raise --avoid=select --avoid=sigprocmask --avoid=sys_types --avoid=threadlib --makefile-name=gnulib.mk --conditional-dependencies --no-libtool --macro-prefix=gl --no-vc-files alloca-opt c-strcase careadlinkat crypto/md5 crypto/sha1 crypto/sha256 crypto/sha512 dtoastr dtotimespec dup2 filemode getloadavg getopt-gnu gettime gettimeofday ignore-value intprops largefile lstat manywarnings mktime pselect pthread_sigmask readlink socklen stat-time stdarg stdio strftime strtoimax strtoumax symlink sys_stat sys_time time timespec-add timespec-sub utimens warnings
 
 
 MOSTLYCLEANFILES += core *.stackdump
@@ -64,6 +64,18 @@
 
 ## end   gnulib module allocator
 
+## begin gnulib module c-ctype
+
+libgnu_a_SOURCES += c-ctype.h c-ctype.c
+
+## end   gnulib module c-ctype
+
+## begin gnulib module c-strcase
+
+libgnu_a_SOURCES += c-strcase.h c-strcasecmp.c c-strncasecmp.c
+
+## end   gnulib module c-strcase
+
 ## begin gnulib module careadlinkat
 
 libgnu_a_SOURCES += careadlinkat.c

=== modified file 'lwlib/ChangeLog'
--- lwlib/ChangeLog	2012-06-26 01:05:39 +0000
+++ lwlib/ChangeLog	2012-06-26 01:35:27 +0000
@@ -1,5 +1,9 @@
 2012-06-26  Paul Eggert  <eggert <at> cs.ucla.edu>
 
+	Use c_strcasecmp for portable ASCII case-insensitive comparison.
+	* lwlib.c: Include c-strcase.h.
+	(lwlib_strcasecmp): Remove.  All uses replaced with c_strcasecmp.
+
 	Clean out last vestiges of the old HAVE_CONFIG_H stuff.
 	* Makefile.in (ALL_CFLAGS): Remove -DHAVE_CONFIG_H.
 	* lwlib-Xaw.c, lwlib-Xlw.c, lwlib-Xm.c, lwlib-utils.c, lwlib.c:

=== modified file 'lwlib/lwlib.c'
--- lwlib/lwlib.c	2012-06-26 01:05:39 +0000
+++ lwlib/lwlib.c	2012-06-26 01:35:27 +0000
@@ -24,6 +24,7 @@
 
 #include <setjmp.h>
 #include <lisp.h>
+#include <c-strcase.h>
 
 #include <sys/types.h>
 #include <stdio.h>
@@ -112,31 +113,6 @@
   return result;
 }
 
-#ifdef HAVE_STRCASECMP
-#define lwlib_strcasecmp(x,y) strcasecmp ((x), (y))
-#else
-
-/* Like strcmp but ignore differences in case.  */
-
-static int
-lwlib_strcasecmp (const char *s1, const char *s2)
-{
-  while (1)
-    {
-      int c1 = *s1++;
-      int c2 = *s2++;
-      if (isupper (c1))
-	c1 = tolower (c1);
-      if (isupper (c2))
-	c2 = tolower (c2);
-      if (c1 != c2)
-	return (c1 > c2 ? 1 : -1);
-      if (c1 == 0)
-	return 0;
-    }
-}
-#endif /* HAVE_STRCASECMP */
-
 static void
 safe_free_str (char *s)
 {
@@ -733,7 +709,7 @@
 {
   const widget_creation_entry* cur;
   for (cur = table; cur->type; cur++)
-    if (!lwlib_strcasecmp (type, cur->type))
+    if (!c_strcasecmp (type, cur->type))
       return cur->function;
   return NULL;
 }

=== modified file 'm4/gnulib-comp.m4'
--- m4/gnulib-comp.m4	2012-06-22 21:17:42 +0000
+++ m4/gnulib-comp.m4	2012-06-26 01:35:27 +0000
@@ -40,6 +40,8 @@
   AC_REQUIRE([gl_PROG_AR_RANLIB])
   # Code from module alloca-opt:
   # Code from module allocator:
+  # Code from module c-ctype:
+  # Code from module c-strcase:
   # Code from module careadlinkat:
   # Code from module clock-time:
   # Code from module crypto/md5:
@@ -518,6 +520,11 @@
   lib/alloca.in.h
   lib/allocator.c
   lib/allocator.h
+  lib/c-ctype.c
+  lib/c-ctype.h
+  lib/c-strcase.h
+  lib/c-strcasecmp.c
+  lib/c-strncasecmp.c
   lib/careadlinkat.c
   lib/careadlinkat.h
   lib/dosname.h

=== modified file 'src/ChangeLog'
--- src/ChangeLog	2012-06-26 01:05:39 +0000
+++ src/ChangeLog	2012-06-26 01:35:27 +0000
@@ -1,5 +1,14 @@
 2012-06-26  Paul Eggert  <eggert <at> cs.ucla.edu>
 
+	Use c_strcasecmp for portable ASCII case-insensitive comparison.
+	* dispextern.h (xstrcasecmp): Remove decl.
+	* dosfns.c, font.c, fontset.c, ftfont.c, image.c, nsfns.m, nsterm.m:
+	* process.c, w32.h, w32font.c, xfaces.c, xfns.c, xfont.c:
+	Include <c-strcase.h>.  Replace all uses of xstrcasecmp with
+	c_strcasecmp.
+	* xfaces.c (xstrcasecmp): Remove.
+	* xfont.c (compare_font_names): Rewrite to avoid casts.
+
 	Clean out last vestiges of the old HAVE_CONFIG_H stuff.
 	* Makefile.in (ALL_CFLAGS):
 	* makefile.w32-in (LOCAL_FLAGS): Remove -DHAVE_CONFIG_H.

=== modified file 'src/dispextern.h'
--- src/dispextern.h	2012-06-25 14:07:04 +0000
+++ src/dispextern.h	2012-06-26 01:35:27 +0000
@@ -3216,11 +3216,6 @@
 char *choose_face_font (struct frame *, Lisp_Object *, Lisp_Object,
                         int *);
 void prepare_face_for_display (struct frame *, struct face *);
-#ifdef HAVE_STRCASECMP
-#define xstrcasecmp(x,y) strcasecmp ((x), (y))
-#else
-int xstrcasecmp (const char *, const char *);
-#endif
 int lookup_named_face (struct frame *, Lisp_Object, int);
 int lookup_basic_face (struct frame *, int);
 int smaller_face (struct frame *, int, int);

=== modified file 'src/dosfns.c'
--- src/dosfns.c	2012-06-19 16:56:28 +0000
+++ src/dosfns.c	2012-06-26 01:35:27 +0000
@@ -25,6 +25,7 @@
 #include <stdio.h>
 #include <dos.h>
 #include <setjmp.h>
+#include <c-strcase.h>
 #include "lisp.h"
 #include "character.h"
 #include "buffer.h"
@@ -396,7 +397,7 @@
   int i;
 
   for (i = 0; i < sizeof (vga_colors) / sizeof (vga_colors[0]); i++)
-    if (xstrcasecmp (name, vga_colors[i]) == 0)
+    if (c_strcasecmp (name, vga_colors[i]) == 0)
       return i;
 
   return
@@ -764,4 +765,3 @@
   dos_decimal_point = 0;
 }
 #endif /* MSDOS */
-

=== modified file 'src/font.c'
--- src/font.c	2012-06-19 16:56:28 +0000
+++ src/font.c	2012-06-26 01:35:27 +0000
@@ -24,6 +24,7 @@
 #include <float.h>
 #include <stdio.h>
 #include <ctype.h>
+#include <c-strcase.h>
 #include <setjmp.h>
 
 #include "lisp.h"
@@ -346,7 +347,7 @@
 	for (j = 1; j < ASIZE (AREF (table, i)); j++)
 	  {
 	    elt = AREF (AREF (table, i), j);
-	    if (xstrcasecmp (s, SSDATA (SYMBOL_NAME (elt))) == 0)
+	    if (c_strcasecmp (s, SSDATA (SYMBOL_NAME (elt))) == 0)
 	      return ((XINT (AREF (AREF (table, i), 0)) << 8)
 		      | (i << 4) | (j - 1));
 	  }

=== modified file 'src/fontset.c'
--- src/fontset.c	2012-06-16 12:24:15 +0000
+++ src/fontset.c	2012-06-26 01:35:27 +0000
@@ -29,6 +29,7 @@
 #include <config.h>
 #include <stdio.h>
 #include <setjmp.h>
+#include <c-strcase.h>
 
 #include "lisp.h"
 #include "blockinput.h"
@@ -1173,7 +1174,7 @@
       this_name = FONTSET_NAME (fontset);
       if (name_pattern == 1
 	  ? fast_string_match_ignore_case (name, this_name) >= 0
-	  : !xstrcasecmp (SSDATA (name), SSDATA (this_name)))
+	  : !c_strcasecmp (SSDATA (name), SSDATA (this_name)))
 	return i;
     }
   return -1;

=== modified file 'src/ftfont.c'
--- src/ftfont.c	2012-06-13 00:26:40 +0000
+++ src/ftfont.c	2012-06-26 01:35:27 +0000
@@ -26,6 +26,8 @@
 #include <fontconfig/fontconfig.h>
 #include <fontconfig/fcfreetype.h>
 
+#include <c-strcase.h>
+
 #include "lisp.h"
 #include "dispextern.h"
 #include "frame.h"
@@ -166,8 +168,8 @@
 
 #ifdef FC_FONTFORMAT
   if ((FcPatternGetString (p, FC_FONTFORMAT, 0, &fcstr) == FcResultMatch)
-      && xstrcasecmp ((char *) fcstr, "bdf") != 0
-      && xstrcasecmp ((char *) fcstr, "pcf") != 0)
+      && c_strcasecmp ((char *) fcstr, "bdf") != 0
+      && c_strcasecmp ((char *) fcstr, "pcf") != 0)
     /* Not a BDF nor PCF font.  */
     return Qnil;
 #endif
@@ -183,10 +185,10 @@
       end = newstr + (end - str);
       str = newstr;
     }
-  if (xstrcasecmp (str, "Regular") == 0
-      || xstrcasecmp (str, "Bold") == 0
-      || xstrcasecmp (str, "Oblique") == 0
-      || xstrcasecmp (str, "Italic") == 0)
+  if (c_strcasecmp (str, "Regular") == 0
+      || c_strcasecmp (str, "Bold") == 0
+      || c_strcasecmp (str, "Oblique") == 0
+      || c_strcasecmp (str, "Italic") == 0)
     return Qnil;
   adstyle = font_intern_prop (str, end - str, 1);
   if (font_style_to_value (FONT_WIDTH_INDEX, adstyle, 0) >= 0)
@@ -1051,12 +1053,12 @@
 
 	  if (! NILP (adstyle)
 	      && (NILP (this_adstyle)
-		  || xstrcasecmp (SSDATA (SYMBOL_NAME (adstyle)),
-				  SSDATA (SYMBOL_NAME (this_adstyle))) != 0))
+		  || c_strcasecmp (SSDATA (SYMBOL_NAME (adstyle)),
+				   SSDATA (SYMBOL_NAME (this_adstyle))) != 0))
 	    continue;
 	  if (langname
 	      && ! NILP (this_adstyle)
-	      && xstrcasecmp (langname, SSDATA (SYMBOL_NAME (this_adstyle))))
+	      && c_strcasecmp (langname, SSDATA (SYMBOL_NAME (this_adstyle))))
 	    continue;
 	}
       entity = ftfont_pattern_entity (fontset->fonts[i],
@@ -2625,13 +2627,13 @@
       if (len >= 4)
 	{
 	  str = (FcChar8 *) (SDATA (filename) + len - 4);
-	  if (xstrcasecmp ((char *) str, ".ttf") == 0)
+	  if (c_strcasecmp ((char *) str, ".ttf") == 0)
 	    return intern ("truetype");
-	  if (xstrcasecmp ((char *) str, ".pfb") == 0)
+	  if (c_strcasecmp ((char *) str, ".pfb") == 0)
 	    return intern ("type1");
-	  if (xstrcasecmp ((char *) str, ".pcf") == 0)
+	  if (c_strcasecmp ((char *) str, ".pcf") == 0)
 	    return intern ("pcf");
-	  if (xstrcasecmp ((char *) str, ".bdf") == 0)
+	  if (c_strcasecmp ((char *) str, ".bdf") == 0)
 	    return intern ("bdf");
 	}
     }

=== modified file 'src/image.c'
--- src/image.c	2012-06-24 17:39:14 +0000
+++ src/image.c	2012-06-26 01:35:27 +0000
@@ -21,6 +21,7 @@
 #include <stdio.h>
 #include <math.h>
 #include <ctype.h>
+#include <c-strcase.h>
 #include <unistd.h>
 
 #ifdef HAVE_PNG
@@ -3969,7 +3970,7 @@
 
 	  if (CONSP (specified_color) && STRINGP (XCDR (specified_color)))
 	    {
-	      if (xstrcasecmp (SSDATA (XCDR (specified_color)), "None") == 0)
+	      if (c_strcasecmp (SSDATA (XCDR (specified_color)), "None") == 0)
 		color_val = Qt;
 	      else if (x_defined_color (f, SDATA (XCDR (specified_color)),
 					&cdef, 0))
@@ -3978,7 +3979,7 @@
 	}
       if (NILP (color_val) && max_key > 0)
 	{
-	  if (xstrcasecmp (max_color, "None") == 0)
+	  if (c_strcasecmp (max_color, "None") == 0)
 	    color_val = Qt;
 	  else if (x_defined_color (f, max_color, &cdef, 0))
 	    color_val = make_number (cdef.pixel);

=== modified file 'src/nsfns.m'
--- src/nsfns.m	2012-06-16 12:24:15 +0000
+++ src/nsfns.m	2012-06-26 01:35:27 +0000
@@ -33,6 +33,7 @@
 #include <signal.h>
 #include <math.h>
 #include <setjmp.h>
+#include <c-strcase.h>
 
 #include "lisp.h"
 #include "blockinput.h"
@@ -2227,8 +2228,8 @@
 
   res = ns_get_defaults_value (toCheck);
   return !res ? NULL :
-      (!strncasecmp (res, "YES", 3) ? "true" :
-          (!strncasecmp (res, "NO", 2) ? "false" : res));
+      (!c_strncasecmp (res, "YES", 3) ? "true" :
+          (!c_strncasecmp (res, "NO", 2) ? "false" : res));
 }
 
 

=== modified file 'src/nsterm.m'
--- src/nsterm.m	2012-06-22 21:17:42 +0000
+++ src/nsterm.m	2012-06-26 01:35:27 +0000
@@ -36,6 +36,7 @@
 #include <signal.h>
 #include <unistd.h>
 #include <setjmp.h>
+#include <c-strcase.h>
 
 #include "lisp.h"
 #include "blockinput.h"
@@ -3855,9 +3856,9 @@
     {
       double f;
       char *pos;
-      if (strcasecmp (value, "YES") == 0)
+      if (c_strcasecmp (value, "YES") == 0)
         *result = yesval;
-      else if (strcasecmp (value, "NO") == 0)
+      else if (c_strcasecmp (value, "NO") == 0)
         *result = noval;
       else if (is_float && (f = strtod (value, &pos), pos != value))
         *result = make_float (f);
@@ -6074,7 +6075,7 @@
 
   if (nr_screens == 1)
     return [super constrainFrameRect:frameRect toScreen:screen];
-  
+
   if (f->output_data.ns->dont_constrain
       || ns_menu_bar_should_be_hidden ())
     return frameRect;

=== modified file 'src/process.c'
--- src/process.c	2012-06-24 20:34:48 +0000
+++ src/process.c	2012-06-26 01:35:27 +0000
@@ -31,6 +31,7 @@
 
 #include <unistd.h>
 #include <fcntl.h>
+#include <c-strcase.h>
 
 #include "lisp.h"
 
@@ -6124,7 +6125,7 @@
     }
 
 #define parse_signal(NAME, VALUE)		\
-  else if (!xstrcasecmp (name, NAME))		\
+  else if (!c_strcasecmp (name, NAME))		\
     XSETINT (sigcode, VALUE)
 
   if (INTEGERP (sigcode))

=== modified file 'src/w32.c'
--- src/w32.c	2012-06-23 16:56:47 +0000
+++ src/w32.c	2012-06-26 01:35:27 +0000
@@ -140,7 +140,7 @@
 #include "ndir.h"
 #include "w32heap.h"
 #include "systime.h"
-#include "dispextern.h"		/* for xstrcasecmp */
+#include "c-strcase.h"
 #include "coding.h"		/* for Vlocale_coding_system */
 
 #include "careadlinkat.h"
@@ -1025,7 +1025,7 @@
   if (!pw)
     return pw;
 
-  if (xstrcasecmp (name, pw->pw_name))
+  if (c_strcasecmp (name, pw->pw_name))
     return NULL;
 
   return pw;
@@ -1076,7 +1076,7 @@
     {
       strcpy (dflt_passwd.pw_name, uname);
       /* Determine a reasonable uid value.  */
-      if (xstrcasecmp ("administrator", uname) == 0)
+      if (c_strcasecmp ("administrator", uname) == 0)
 	{
 	  dflt_passwd.pw_uid = 500; /* well-known Administrator uid */
 	  dflt_passwd.pw_gid = 513; /* well-known None gid */
@@ -1118,7 +1118,7 @@
   else if (GetUserName (uname, &ulength))
     {
       strcpy (dflt_passwd.pw_name, uname);
-      if (xstrcasecmp ("administrator", uname) == 0)
+      if (c_strcasecmp ("administrator", uname) == 0)
 	dflt_passwd.pw_uid = 0;
       else
 	dflt_passwd.pw_uid = 123;
@@ -1674,7 +1674,7 @@
 	abort ();
       *p = 0;
 
-      if ((p = strrchr (modname, '\\')) && xstrcasecmp (p, "\\bin") == 0)
+      if ((p = strrchr (modname, '\\')) && c_strcasecmp (p, "\\bin") == 0)
 	{
 	  char buf[SET_ENV_BUF_SIZE];
 
@@ -1690,7 +1690,7 @@
       /* FIXME: should use substring of get_emacs_configuration ().
 	 But I don't think the Windows build supports alpha, mips etc
          anymore, so have taken the easy option for now.  */
-      else if (p && xstrcasecmp (p, "\\i386") == 0)
+      else if (p && c_strcasecmp (p, "\\i386") == 0)
 	{
 	  *p = 0;
 	  p = strrchr (modname, '\\');
@@ -1698,7 +1698,7 @@
 	    {
 	      *p = 0;
 	      p = strrchr (modname, '\\');
-	      if (p && xstrcasecmp (p, "\\src") == 0)
+	      if (p && c_strcasecmp (p, "\\src") == 0)
 		{
 		  char buf[SET_ENV_BUF_SIZE];
 
@@ -2101,7 +2101,7 @@
   volume_info_data * info;
 
   for (info = volume_cache; info; info = info->next)
-    if (xstrcasecmp (info->root_dir, root_dir) == 0)
+    if (c_strcasecmp (info->root_dir, root_dir) == 0)
       break;
   return info;
 }
@@ -2379,10 +2379,10 @@
   char * p = strrchr (name, '.');
   return
     (p != NULL
-     && (xstrcasecmp (p, ".exe") == 0 ||
-	 xstrcasecmp (p, ".com") == 0 ||
-	 xstrcasecmp (p, ".bat") == 0 ||
-	 xstrcasecmp (p, ".cmd") == 0));
+     && (c_strcasecmp (p, ".exe") == 0 ||
+	 c_strcasecmp (p, ".com") == 0 ||
+	 c_strcasecmp (p, ".bat") == 0 ||
+	 c_strcasecmp (p, ".cmd") == 0));
 }
 
 /* Emulate the Unix directory procedures opendir, closedir,
@@ -3450,7 +3450,7 @@
       if (dir_find_handle != INVALID_HANDLE_VALUE
 	  && strnicmp (name, dir_pathname, len) == 0
 	  && IS_DIRECTORY_SEP (name[len])
-	  && xstrcasecmp (name + len + 1, dir_static.d_name) == 0)
+	  && c_strcasecmp (name + len + 1, dir_static.d_name) == 0)
 	{
 	  /* This was the last entry returned by readdir.  */
 	  wfd = dir_find_data;
@@ -3673,10 +3673,10 @@
 #if 0 /* no way of knowing the filename */
       char * p = strrchr (name, '.');
       if (p != NULL &&
-	  (xstrcasecmp (p, ".exe") == 0 ||
-	   xstrcasecmp (p, ".com") == 0 ||
-	   xstrcasecmp (p, ".bat") == 0 ||
-	   xstrcasecmp (p, ".cmd") == 0))
+	  (c_strcasecmp (p, ".exe") == 0 ||
+	   c_strcasecmp (p, ".com") == 0 ||
+	   c_strcasecmp (p, ".bat") == 0 ||
+	   c_strcasecmp (p, ".cmd") == 0))
 	permission |= S_IEXEC;
 #endif
     }
@@ -4290,7 +4290,7 @@
       if (result)
 	{
 	  /* Determine a reasonable euid and gid values.  */
-	  if (xstrcasecmp ("administrator", uname) == 0)
+	  if (c_strcasecmp ("administrator", uname) == 0)
 	    {
 	      euid = 500;	/* well-known Administrator uid */
 	      egid = 513;	/* well-known None gid */
@@ -4351,7 +4351,7 @@
 	 user.  */
       else if (GetUserName (uname, &ulength))
 	{
-	  if (xstrcasecmp ("administrator", uname) == 0)
+	  if (c_strcasecmp ("administrator", uname) == 0)
 	    euid = 0;
 	  else
 	    euid = 123;

=== modified file 'src/w32font.c'
--- src/w32font.c	2012-05-02 10:12:13 +0000
+++ src/w32font.c	2012-06-26 01:35:27 +0000
@@ -20,6 +20,7 @@
 #include <windows.h>
 #include <math.h>
 #include <ctype.h>
+#include <c-strcase.h>
 #include <commdlg.h>
 #include <setjmp.h>
 
@@ -1466,7 +1467,7 @@
      to avoid non-truetype fonts, and ends up mixing the Type-1 Helvetica
      with Arial's characteristics, since that attempt to use TrueType works
      some places, but not others.  */
-  if (!xstrcasecmp (font->lfFaceName, "helvetica"))
+  if (!c_strcasecmp (font->lfFaceName, "helvetica"))
     {
       strncpy (full_iname, full_name, LF_FULLFACESIZE);
       full_iname[LF_FULLFACESIZE] = 0;
@@ -1474,7 +1475,7 @@
       return strstr ("helvetica", full_iname) != NULL;
     }
   /* Same for Helv.  */
-  if (!xstrcasecmp (font->lfFaceName, "helv"))
+  if (!c_strcasecmp (font->lfFaceName, "helv"))
     {
       strncpy (full_iname, full_name, LF_FULLFACESIZE);
       full_iname[LF_FULLFACESIZE] = 0;
@@ -1484,8 +1485,8 @@
 
   /* Since Times is mapped to Times New Roman, a substring
      match is not sufficient to filter out the bogus match.  */
-  else if (!xstrcasecmp (font->lfFaceName, "times"))
-    return xstrcasecmp (full_name, "times") == 0;
+  else if (!c_strcasecmp (font->lfFaceName, "times"))
+    return c_strcasecmp (full_name, "times") == 0;
 
   return 1;
 }
@@ -1660,7 +1661,7 @@
   if (NILP (this_entry))
     {
       /* At startup, we want iso8859-1 fonts to come up properly. */
-      if (xstrcasecmp (charset, "iso8859-1") == 0)
+      if (c_strcasecmp (charset, "iso8859-1") == 0)
         return ANSI_CHARSET;
       else
         return DEFAULT_CHARSET;

=== modified file 'src/w32proc.c'
--- src/w32proc.c	2012-06-23 12:44:42 +0000
+++ src/w32proc.c	2012-06-26 01:35:27 +0000
@@ -50,6 +50,8 @@
 #include <langinfo.h>
 #endif
 
+#include <c-strcase.h>
+
 #include "lisp.h"
 #include "w32.h"
 #include "w32heap.h"
@@ -58,7 +60,6 @@
 #include "process.h"
 #include "syssignal.h"
 #include "w32term.h"
-#include "dispextern.h"		/* for xstrcasecmp */
 #include "coding.h"
 
 #define RVA_TO_PTR(var,section,filedata) \
@@ -599,10 +600,10 @@
   p = strrchr (filename, '.');
 
   /* We can only identify DOS .com programs from the extension. */
-  if (p && xstrcasecmp (p, ".com") == 0)
+  if (p && c_strcasecmp (p, ".com") == 0)
     *is_dos_app = TRUE;
-  else if (p && (xstrcasecmp (p, ".bat") == 0
-		 || xstrcasecmp (p, ".cmd") == 0))
+  else if (p && (c_strcasecmp (p, ".bat") == 0
+		 || c_strcasecmp (p, ".cmd") == 0))
     {
       /* A DOS shell script - it appears that CreateProcess is happy to
 	 accept this (somewhat surprisingly); presumably it looks at

=== modified file 'src/xfaces.c'
--- src/xfaces.c	2012-06-25 14:07:04 +0000
+++ src/xfaces.c	2012-06-26 01:35:27 +0000
@@ -205,6 +205,7 @@
 #include <sys/stat.h>
 #include <stdio.h>              /* This needs to be before termchar.h */
 #include <setjmp.h>
+#include <c-strcase.h>
 
 #include "lisp.h"
 #include "character.h"
@@ -716,30 +717,6 @@
 }
 #endif  /* HAVE_NS */
 
-#ifndef HAVE_STRCASECMP
-/* Like strcasecmp/stricmp.  Used to compare parts of font names which
-   are in ISO8859-1.  */
-
-int
-xstrcasecmp (const char *s1, const char *s2)
-{
-  while (*s1 && *s2)
-    {
-      unsigned char b1 = *s1;
-      unsigned char b2 = *s2;
-      unsigned char c1 = tolower (b1);
-      unsigned char c2 = tolower (b2);
-      if (c1 != c2)
-	return c1 < c2 ? -1 : 1;
-      ++s1, ++s2;
-    }
-
-  if (*s1 == 0)
-    return *s2 == 0 ? 0 : -1;
-  return 1;
-}
-#endif /* HAVE_STRCASECMP */
-
 /* If FRAME is nil, return a pointer to the selected frame.
    Otherwise, check that FRAME is a live frame, and return a pointer
    to it.  NPARAM is the parameter number of FRAME, for
@@ -1257,8 +1234,8 @@
 #ifdef HAVE_WINDOW_SYSTEM
     FRAME_WINDOW_P (f)
     ? (!NILP (Fxw_display_color_p (frame))
-       || xstrcasecmp (color_name, "black") == 0
-       || xstrcasecmp (color_name, "white") == 0
+       || c_strcasecmp (color_name, "black") == 0
+       || c_strcasecmp (color_name, "white") == 0
        || (background_p
 	   && face_color_gray_p (f, color_name))
        || (!NILP (Fx_display_grayscale_p (frame))
@@ -2953,7 +2930,7 @@
   else if (EQ (attr, QCunderline))
     {
       int valid_p = 0;
-      
+
       if (UNSPECIFIEDP (value) || IGNORE_DEFFACE_P (value))
 	valid_p = 1;
       else if (NILP (value) || EQ (value, Qt))
@@ -2973,8 +2950,8 @@
               list = CDR_SAFE (list);
               val = CAR_SAFE (list);
               list = CDR_SAFE (list);
-            
-              if(NILP (key) || NILP (val)) 
+
+              if(NILP (key) || NILP (val))
                 {
                   valid_p = 0;
                   break;
@@ -2987,8 +2964,8 @@
                   valid_p = 0;
                   break;
                 }
-              
-              else if (EQ (key, QCstyle) 
+
+              else if (EQ (key, QCstyle)
                        && !(EQ (val, Qline) || EQ (val, Qwave)))
                 {
                   valid_p = 0;
@@ -2996,10 +2973,10 @@
                 }
             }
         }
-      
+
       if (!valid_p)
         signal_error ("Invalid face underline", value);
-      
+
       old_value = LFACE_UNDERLINE (lface);
       LFACE_UNDERLINE (lface) = value;
     }
@@ -3517,13 +3494,13 @@
 
   xassert (STRINGP (value));
 
-  if (xstrcasecmp (SSDATA (value), "on") == 0
-      || xstrcasecmp (SSDATA (value), "true") == 0)
+  if (c_strcasecmp (SSDATA (value), "on") == 0
+      || c_strcasecmp (SSDATA (value), "true") == 0)
     result = Qt;
-  else if (xstrcasecmp (SSDATA (value), "off") == 0
-	   || xstrcasecmp (SSDATA (value), "false") == 0)
+  else if (c_strcasecmp (SSDATA (value), "off") == 0
+	   || c_strcasecmp (SSDATA (value), "false") == 0)
     result = Qnil;
-  else if (xstrcasecmp (SSDATA (value), "unspecified") == 0)
+  else if (c_strcasecmp (SSDATA (value), "unspecified") == 0)
     result = Qunspecified;
   else if (signal_p)
     signal_error ("Invalid face attribute value from X resource", value);
@@ -3542,7 +3519,7 @@
   CHECK_SYMBOL (attr);
   CHECK_STRING (value);
 
-  if (xstrcasecmp (SSDATA (value), "unspecified") == 0)
+  if (c_strcasecmp (SSDATA (value), "unspecified") == 0)
     value = Qunspecified;
   else if (EQ (attr, QCheight))
     {
@@ -4121,10 +4098,10 @@
 {
   xassert (lface_fully_specified_p (lface1)
 	   && lface_fully_specified_p (lface2));
-  return (xstrcasecmp (SSDATA (lface1[LFACE_FAMILY_INDEX]),
-		       SSDATA (lface2[LFACE_FAMILY_INDEX])) == 0
-	  && xstrcasecmp (SSDATA (lface1[LFACE_FOUNDRY_INDEX]),
-			  SSDATA (lface2[LFACE_FOUNDRY_INDEX])) == 0
+  return (c_strcasecmp (SSDATA (lface1[LFACE_FAMILY_INDEX]),
+			SSDATA (lface2[LFACE_FAMILY_INDEX])) == 0
+	  && c_strcasecmp (SSDATA (lface1[LFACE_FOUNDRY_INDEX]),
+			   SSDATA (lface2[LFACE_FOUNDRY_INDEX])) == 0
 	  && EQ (lface1[LFACE_HEIGHT_INDEX], lface2[LFACE_HEIGHT_INDEX])
 	  && EQ (lface1[LFACE_SWIDTH_INDEX], lface2[LFACE_SWIDTH_INDEX])
 	  && EQ (lface1[LFACE_WEIGHT_INDEX], lface2[LFACE_WEIGHT_INDEX])
@@ -4133,8 +4110,8 @@
 	  && (EQ (lface1[LFACE_FONTSET_INDEX], lface2[LFACE_FONTSET_INDEX])
 	      || (STRINGP (lface1[LFACE_FONTSET_INDEX])
 		  && STRINGP (lface2[LFACE_FONTSET_INDEX])
-		  && ! xstrcasecmp (SSDATA (lface1[LFACE_FONTSET_INDEX]),
-				    SSDATA (lface2[LFACE_FONTSET_INDEX]))))
+		  && ! c_strcasecmp (SSDATA (lface1[LFACE_FONTSET_INDEX]),
+				     SSDATA (lface2[LFACE_FONTSET_INDEX]))))
 	  );
 }
 
@@ -5779,7 +5756,7 @@
     }
   else if (CONSP (underline))
     {
-      /* `(:color COLOR :style STYLE)'.  
+      /* `(:color COLOR :style STYLE)'.
          STYLE being one of `line' or `wave'. */
       face->underline_p = 1;
       face->underline_color = 0;
@@ -5821,7 +5798,7 @@
             }
         }
     }
-  
+
   overline = attrs[LFACE_OVERLINE_INDEX];
   if (STRINGP (overline))
     {

=== modified file 'src/xfns.c'
--- src/xfns.c	2012-06-25 10:16:11 +0000
+++ src/xfns.c	2012-06-26 01:35:27 +0000
@@ -21,6 +21,7 @@
 #include <stdio.h>
 #include <math.h>
 #include <setjmp.h>
+#include <c-strcase.h>
 #include <ctype.h>
 #include <unistd.h>
 
@@ -1881,7 +1882,7 @@
 
   /* Make a fontset name from the base font name.  */
   if (xic_default_fontset == base_fontname)
-    { 
+    {
       /* There is no base font name, use the default.  */
       fontsetname = xmalloc (strlen (base_fontname) + 2);
       strcpy (fontsetname, base_fontname);
@@ -3977,7 +3978,7 @@
 
       /* Determine the visual class.  */
       for (i = 0; visual_classes[i].name; ++i)
-	if (xstrcasecmp (s, visual_classes[i].name) == 0)
+	if (c_strcasecmp (s, visual_classes[i].name) == 0)
 	  {
 	    class = visual_classes[i].class;
 	    break;

=== modified file 'src/xfont.c'
--- src/xfont.c	2012-06-13 00:26:40 +0000
+++ src/xfont.c	2012-06-26 01:35:27 +0000
@@ -23,6 +23,7 @@
 #include <stdio.h>
 #include <setjmp.h>
 #include <X11/Xlib.h>
+#include <c-strcase.h>
 
 #include "lisp.h"
 #include "dispextern.h"
@@ -164,8 +165,9 @@
 static int
 compare_font_names (const void *name1, const void *name2)
 {
-  return xstrcasecmp (*(const char **) name1,
-		      *(const char **) name2);
+  char *const *n1 = name1;
+  char *const *n2 = name2;
+  return c_strcasecmp (*n1, *n2);
 }
 
 /* Decode XLFD as iso-8859-1 into OUTPUT, and return the byte length
@@ -398,7 +400,7 @@
 	{
 	  Lisp_Object entity;
 
-	  if (i > 0 && xstrcasecmp (indices[i - 1], indices[i]) == 0)
+	  if (i > 0 && c_strcasecmp (indices[i - 1], indices[i]) == 0)
 	    continue;
 	  entity = font_make_entity ();
 	  xfont_decode_coding_xlfd (indices[i], -1, buf);




Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#11786; Package emacs. (Tue, 26 Jun 2012 16:07:02 GMT) Full text and rfc822 format available.

Message #8 received at 11786 <at> debbugs.gnu.org (full text, mbox):

From: Eli Zaretskii <eliz <at> gnu.org>
To: Paul Eggert <eggert <at> cs.ucla.edu>, Dmitry Antipov <dmantipov <at> yandex.ru>
Cc: 11786 <at> debbugs.gnu.org
Subject: Re: bug#11786: Use c_strcasecmp for portable ASCII
	case-insensitive	comparison
Date: Tue, 26 Jun 2012 19:02:20 +0300
> Date: Mon, 25 Jun 2012 18:42:08 -0700
> From: Paul Eggert <eggert <at> cs.ucla.edu>
> 
> Emacs currently use 'strcasecmp' and 'strncasecmp' for
> case-insensitive comparison but these have problems in multibyte
> locales.  In practice Emacs code really just wants a C-locale
> version of these functions so I'm planning on installing the
> following patch after some more testing.  I'm giving some
> heads-up as this affects the Microsoft ports.

Not related to "Microsoft ports", but can we please step back one
notch and discuss this stuff in a little bit more detail?

First, until revision 108735, committed yesterday by Dmitry, we didn't
use strcasecmp or strncasecmp (except in the NS port, which looks like
an oversight).  We used xtrcasecmp, whose only dependence on the
locale is the tolower function/macro.  Then Dmitry replaced
xstrcasecmp with strcasecmp for those platforms that have it (which I
think means all the supported platforms), for reasons that AFAIK were
never discussed.  Why was that done?

Now you are going to replace strcasecmp with several gnulib modules.

All the calls to xtrcasecmp are for comparing strings that are known
to be plain ASCII: names of fonts, extensions of certain file types,
fixed ASCII strings, etc.  Can tolower fail for these, somehow, in a
locale that uses a multibyte encoding for these strings, and if so,
can you give a practical example of such a failure?

If tolower is good enough for these cases, I suggest that we revert
changes in revision 108735, and perhaps add comments somewhere as to
the reasons why we use that custom function instead of library
functions.

If tolower can fail in some locale, I suggest that we restore
xstrcasecmp, and simply augment it with c_tolower from gnulib, or its
equivalent.   That sounds like a much simpler change to me.

Comments are welcome.

Thanks.




Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#11786; Package emacs. (Tue, 26 Jun 2012 16:30:02 GMT) Full text and rfc822 format available.

Message #11 received at 11786 <at> debbugs.gnu.org (full text, mbox):

From: Andreas Schwab <schwab <at> linux-m68k.org>
To: Eli Zaretskii <eliz <at> gnu.org>
Cc: 11786 <at> debbugs.gnu.org, Paul Eggert <eggert <at> cs.ucla.edu>,
	Dmitry Antipov <dmantipov <at> yandex.ru>
Subject: Re: bug#11786: Use c_strcasecmp for portable ASCII
	case-insensitive	comparison
Date: Tue, 26 Jun 2012 18:25:03 +0200
Eli Zaretskii <eliz <at> gnu.org> writes:

> Can tolower fail for these, somehow, in a locale that uses a multibyte
> encoding for these strings, and if so, can you give a practical
> example of such a failure?

tolower ('I') in a turkish locale.

Andreas.

-- 
Andreas Schwab, schwab <at> linux-m68k.org
GPG Key fingerprint = 58CA 54C7 6D53 942B 1756  01D3 44D5 214B 8276 4ED5
"And now for something completely different."




Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#11786; Package emacs. (Tue, 26 Jun 2012 16:36:02 GMT) Full text and rfc822 format available.

Message #14 received at 11786 <at> debbugs.gnu.org (full text, mbox):

From: Eli Zaretskii <eliz <at> gnu.org>
To: Andreas Schwab <schwab <at> linux-m68k.org>
Cc: 11786 <at> debbugs.gnu.org, eggert <at> cs.ucla.edu, dmantipov <at> yandex.ru
Subject: Re: bug#11786: Use c_strcasecmp for portable ASCII
	case-insensitive	comparison
Date: Tue, 26 Jun 2012 19:31:11 +0300
> From: Andreas Schwab <schwab <at> linux-m68k.org>
> Cc: Paul Eggert <eggert <at> cs.ucla.edu>,  Dmitry Antipov <dmantipov <at> yandex.ru>,  11786 <at> debbugs.gnu.org
> Date: Tue, 26 Jun 2012 18:25:03 +0200
> 
> Eli Zaretskii <eliz <at> gnu.org> writes:
> 
> > Can tolower fail for these, somehow, in a locale that uses a multibyte
> > encoding for these strings, and if so, can you give a practical
> > example of such a failure?
> 
> tolower ('I') in a turkish locale.

OK, but that's not an issue with multibyte locales.

Anyway, I think having a custom replacement for tolower, perhaps using
the code of c_tolower from gnulib or its equivalent, will resolve
this.  Am I missing something?




Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#11786; Package emacs. (Tue, 26 Jun 2012 16:44:02 GMT) Full text and rfc822 format available.

Message #17 received at 11786 <at> debbugs.gnu.org (full text, mbox):

From: Andreas Schwab <schwab <at> linux-m68k.org>
To: Eli Zaretskii <eliz <at> gnu.org>
Cc: 11786 <at> debbugs.gnu.org, eggert <at> cs.ucla.edu, dmantipov <at> yandex.ru
Subject: Re: bug#11786: Use c_strcasecmp for portable ASCII
	case-insensitive	comparison
Date: Tue, 26 Jun 2012 18:39:02 +0200
Eli Zaretskii <eliz <at> gnu.org> writes:

>> From: Andreas Schwab <schwab <at> linux-m68k.org>
>> Cc: Paul Eggert <eggert <at> cs.ucla.edu>,  Dmitry Antipov <dmantipov <at> yandex.ru>,  11786 <at> debbugs.gnu.org
>> Date: Tue, 26 Jun 2012 18:25:03 +0200
>> 
>> Eli Zaretskii <eliz <at> gnu.org> writes:
>> 
>> > Can tolower fail for these, somehow, in a locale that uses a multibyte
>> > encoding for these strings, and if so, can you give a practical
>> > example of such a failure?
>> 
>> tolower ('I') in a turkish locale.
>
> OK, but that's not an issue with multibyte locales.

It's an issue with both tr_TR.ISO-8859-8 and tr_TR.UTF-8.  In the former
case you get a non-ASCII character, in the latter case you get an upper
case character.

Andreas.

-- 
Andreas Schwab, schwab <at> linux-m68k.org
GPG Key fingerprint = 58CA 54C7 6D53 942B 1756  01D3 44D5 214B 8276 4ED5
"And now for something completely different."




Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#11786; Package emacs. (Tue, 26 Jun 2012 17:07:02 GMT) Full text and rfc822 format available.

Message #20 received at 11786 <at> debbugs.gnu.org (full text, mbox):

From: Dmitry Antipov <dmantipov <at> yandex.ru>
To: Eli Zaretskii <eliz <at> gnu.org>
Cc: 11786 <at> debbugs.gnu.org, Paul Eggert <eggert <at> cs.ucla.edu>
Subject: Re: bug#11786: Use c_strcasecmp for portable ASCII case-insensitive
	comparison
Date: Tue, 26 Jun 2012 21:04:24 +0400
On 06/26/2012 08:02 PM, Eli Zaretskii wrote:

> First, until revision 108735, committed yesterday by Dmitry, we didn't
> use strcasecmp or strncasecmp (except in the NS port, which looks like
> an oversight).  We used xtrcasecmp, whose only dependence on the
> locale is the tolower function/macro.  Then Dmitry replaced
> xstrcasecmp with strcasecmp for those platforms that have it (which I
> think means all the supported platforms), for reasons that AFAIK were
> never discussed.  Why was that done?

It was an attempt to get rid from the zoo of strcase(n)cmp implementations
(one in etags.c, one in lwlib.c and next one in xfaces.c). I assumed that
these library functions, if available, should work correctly regardless
from the locale on any non-ancient system. If that is not true, gnulib
module may be a workaround.

Dmitry






Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#11786; Package emacs. (Tue, 26 Jun 2012 17:21:01 GMT) Full text and rfc822 format available.

Message #23 received at 11786 <at> debbugs.gnu.org (full text, mbox):

From: Eli Zaretskii <eliz <at> gnu.org>
To: Dmitry Antipov <dmantipov <at> yandex.ru>
Cc: 11786 <at> debbugs.gnu.org, eggert <at> cs.ucla.edu
Subject: Re: bug#11786: Use c_strcasecmp for portable ASCII case-insensitive
	comparison
Date: Tue, 26 Jun 2012 20:16:25 +0300
> Date: Tue, 26 Jun 2012 21:04:24 +0400
> From: Dmitry Antipov <dmantipov <at> yandex.ru>
> CC: Paul Eggert <eggert <at> cs.ucla.edu>, 11786 <at> debbugs.gnu.org
> 
> It was an attempt to get rid from the zoo of strcase(n)cmp implementations
> (one in etags.c, one in lwlib.c and next one in xfaces.c).

Thanks for the explanation.

I was talking only about xtrcasecmp, defined on xfaces.c.  lwlib.c can
use it, if we want.  As for etags, I don't care much, but pulling in
another bunch of gnulib modules just for its sake sounds gross to me.

> I assumed that these library functions, if available, should work
> correctly regardless from the locale on any non-ancient system.

It's actually the other way around: to DTRT, these library functions
_must_ be locale-dependent, because the collation sequence might be
different in each locale, even for locales that use the same Latin
characters.

> If that is not true, gnulib module may be a workaround.

We already had a workaround for that, so I see no reason to use that
of gnulib.




Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#11786; Package emacs. (Tue, 26 Jun 2012 17:30:02 GMT) Full text and rfc822 format available.

Message #26 received at 11786 <at> debbugs.gnu.org (full text, mbox):

From: Paul Eggert <eggert <at> cs.ucla.edu>
To: Eli Zaretskii <eliz <at> gnu.org>
Cc: 11786 <at> debbugs.gnu.org, dmantipov <at> yandex.ru,
	Andreas Schwab <schwab <at> linux-m68k.org>
Subject: Re: bug#11786: Use c_strcasecmp for portable ASCII case-insensitive
	comparison
Date: Tue, 26 Jun 2012 10:25:17 -0700
On 06/26/2012 09:31 AM, Eli Zaretskii wrote:
> I think having a custom replacement for tolower, perhaps using
> the code of c_tolower from gnulib or its equivalent, will resolve
> this.

Yes, that's right, and that's why Emacs should use
gnulib c_strcasecmp.  c_strcasecmp does what
you're saying (it uses c_tolower), and it's
off-the-shelf code, so it means Emacs can get rid of
etags_strcasecmp, lwlib_strcasecmp, and xstrcasecmp
(all of which do essentially the same thing).  This
shrinks and simplifies the source code of Emacs proper.

This change was prompted by Dmitry's recent change to use
strcasecmp.  That change simplified Emacs
but introduced portability problems.  This new change
further simplifies Emacs proper and also fixes
portability problems.




Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#11786; Package emacs. (Tue, 26 Jun 2012 18:26:02 GMT) Full text and rfc822 format available.

Message #29 received at 11786 <at> debbugs.gnu.org (full text, mbox):

From: Eli Zaretskii <eliz <at> gnu.org>
To: Paul Eggert <eggert <at> cs.ucla.edu>
Cc: 11786 <at> debbugs.gnu.org, dmantipov <at> yandex.ru, schwab <at> linux-m68k.org
Subject: Re: bug#11786: Use c_strcasecmp for portable ASCII case-insensitive
	comparison
Date: Tue, 26 Jun 2012 21:21:12 +0300
> Date: Tue, 26 Jun 2012 10:25:17 -0700
> From: Paul Eggert <eggert <at> cs.ucla.edu>
> CC: Andreas Schwab <schwab <at> linux-m68k.org>, dmantipov <at> yandex.ru, 
>  11786 <at> debbugs.gnu.org
> 
> c_strcasecmp does what you're saying (it uses c_tolower), and it's
> off-the-shelf code

So is xstrcasecmp.

> This shrinks and simplifies the source code of Emacs proper.

Your change neither shrinks nor simplifies anything.  It does the
exact opposite, in fact.




Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#11786; Package emacs. (Tue, 26 Jun 2012 20:33:02 GMT) Full text and rfc822 format available.

Message #32 received at 11786 <at> debbugs.gnu.org (full text, mbox):

From: Paul Eggert <eggert <at> cs.ucla.edu>
To: Eli Zaretskii <eliz <at> gnu.org>
Cc: 11786 <at> debbugs.gnu.org, dmantipov <at> yandex.ru, schwab <at> linux-m68k.org
Subject: Re: bug#11786: Use c_strcasecmp for portable ASCII case-insensitive
	comparison
Date: Tue, 26 Jun 2012 13:28:00 -0700
On 06/26/2012 11:21 AM, Eli Zaretskii wrote:
> So is xstrcasecmp.

And etags_strcasecmp.  And lwlib_strcasecmp.

>> > This shrinks and simplifies the source code of Emacs proper.
> Your change neither shrinks nor simplifies anything.

Sure it does.  It coalesces three instances of the
same code into one.  And it shrinks the source of
Emacs proper (i.e., the part that isn't automatically
generated).




Reply sent to Paul Eggert <eggert <at> cs.ucla.edu>:
You have taken responsibility. (Fri, 06 Jul 2012 21:20:02 GMT) Full text and rfc822 format available.

Notification sent to Paul Eggert <eggert <at> cs.ucla.edu>:
bug acknowledged by developer. (Fri, 06 Jul 2012 21:20:02 GMT) Full text and rfc822 format available.

Message #37 received at 11786-done <at> debbugs.gnu.org (full text, mbox):

From: Paul Eggert <eggert <at> cs.ucla.edu>
To: Eli Zaretskii <eliz <at> gnu.org>
Cc: 11786-done <at> debbugs.gnu.org, dmantipov <at> yandex.ru, schwab <at> linux-m68k.org
Subject: Re: bug#11786: Use c_strcasecmp for portable ASCII case-insensitive
	comparison
Date: Fri, 06 Jul 2012 14:14:06 -0700
No further comment, and there is a bug to fix here,
with no other proposal on the table.

I refactored to trim down the size of the patch, to
make it less intrusive into the src directory and
I hope to ameliorate at least some of the objections,
and installed the result as trunk bzr 108922.  Since
the bug is now fixed I'll mark it as done, but of course
further code improvements are welcome.




bug archived. Request was from Debbugs Internal Request <help-debbugs <at> gnu.org> to internal_control <at> debbugs.gnu.org. (Sat, 04 Aug 2012 11:24:10 GMT) Full text and rfc822 format available.

This bug report was last modified 11 years and 272 days ago.

Previous Next


GNU bug tracking system
Copyright (C) 1999 Darren O. Benham, 1997,2003 nCipher Corporation Ltd, 1994-97 Ian Jackson.