This is the mail archive of the gdb-patches@sourceware.org mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: [patch 3/3] case insensitive: the fix [rediff]


On Fri, 22 Apr 2011 21:05:07 +0200, Eli Zaretskii wrote:
> This @table will look weird in the manual: it produces lines that
> begin with a lower-case letter.  Perhaps reorder thusly:

OK, thanks for the review.


Regards,
Jan


gdb/doc/
2011-04-22  Jan Kratochvil  <jan.kratochvil@redhat.com>
	    Eli Zaretskii  <eliz@gnu.org>

	* gdb.texinfo (Index Section Format): Change the version to 5.
	Describe the different formula.

gdb/
2011-04-08  Jan Kratochvil  <jan.kratochvil@redhat.com>

	* dwarf2read.c: Include ctype.h.
	(struct mapped_index): New field version.
	(mapped_index_string_hash): New parameter index_version.  New comment
	for it.  Call tolower appropriately.
	(find_slot_in_mapped_hash): New variable cmp, initialize it, use it.
	Choose the right index version for mapped_index_string_hash.
	(dwarf2_read_index): Support also the index version 5.  Initialize the
	new struct mapped_index field version.
	(hash_strtab_entry): Pass INT_MAX for the new parameter, explain why.
	(find_slot): Explain the version needs.  Pass INT_MAX for the new
	parameter.
	(write_psymtabs_to_index): Produce version 5.
	* minsyms.c (lookup_minimal_symbol): New variable cmp, initialize it,
	use it.  New comment for SYMBOL_MATCHES_SEARCH_NAME.
	* psymtab.c (lookup_partial_symbol): Find the
	SYMBOL_MATCHES_SEARCH_NAME start of the found block of matching
	entries.
	* symtab.c (lookup_symbol_in_language): Remove the case_sensitive_off
	NAME lowercasing.
	(search_symbols): Pass REG_ICASE to regcomp for case_sensitive_off.
	(completion_list_add_name): New variable ncmp, initialize it, use it.
	* symtab.h (SYMBOL_HASH_NEXT): Always call tolower.
	* utils.c (strcmp_iw): Support case_sensitive_off.
	(strcmp_iw_ordered): Sort in a way compatible with case_sensitive_off.
	New function comment part.  New variables saved_string1,
	saved_string2 and case_pass.  Add a proper second pass.

gdb/testsuite/
2011-04-08  Jan Kratochvil  <jan.kratochvil@redhat.com>

	* gdb.base/fortran-sym-case.c: New file.
	* gdb.base/fortran-sym-case.exp: New file.
	* gdb.dwarf2/dw2-case-insensitive-debug.S: New file.
	* gdb.dwarf2/dw2-case-insensitive.c: New file.
	* gdb.dwarf2/dw2-case-insensitive.exp: New file.

--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -36940,7 +36940,8 @@ unless otherwise noted:
 
 @enumerate
 @item
-The version number, currently 4.  Versions 1, 2 and 3 are obsolete.
+The version number, currently 5.  Versions 1, 2 and 3 are obsolete.
+Version 4 differs by its hashing function.
 
 @item
 The offset, from the start of the file, of the CU list.
@@ -37008,9 +37009,18 @@ valid index for both a string and a CU vector.
 The hash value for a table entry is computed by applying an
 iterative hash function to the symbol's name.  Starting with an
 initial value of @code{r = 0}, each (unsigned) character @samp{c} in
-the string is incorporated into the hash using the formula
-@code{r = r * 67 + c - 113}.  The terminating @samp{\0} is not
-incorporated into the hash.
+the string is incorporated into the hash using the formula depending on the
+index version:
+
+@table @asis
+@item Version 4
+The formula is @code{r = r * 67 + c - 113}.
+
+@item Version 5
+The formula is @code{r = r * 67 + tolower (c) - 113}.
+@end table
+
+The terminating @samp{\0} is not incorporated into the hash.
 
 The step size used in the hash table is computed via
 @code{((hash * 17) & (size - 1)) | 1}, where @samp{hash} is the hash
--- a/gdb/dwarf2read.c
+++ b/gdb/dwarf2read.c
@@ -149,6 +149,9 @@ DEF_VEC_I (offset_type);
    a comment by the code that writes the index.  */
 struct mapped_index
 {
+  /* Index data format version.  */
+  int version;
+
   /* The total length of the buffer.  */
   off_t total_size;
 
@@ -1972,17 +1975,23 @@ create_addrmap_from_index (struct objfile *objfile, struct mapped_index *index)
    SYMBOL_HASH_NEXT, but we keep a separate copy to maintain control over the
    implementation.  This is necessary because the hash function is tied to the
    format of the mapped index file.  The hash values do not have to match with
-   SYMBOL_HASH_NEXT.  */
+   SYMBOL_HASH_NEXT.
+   
+   Use INT_MAX for INDEX_VERSION if you generate the current index format.  */
 
 static hashval_t
-mapped_index_string_hash (const void *p)
+mapped_index_string_hash (int index_version, const void *p)
 {
   const unsigned char *str = (const unsigned char *) p;
   hashval_t r = 0;
   unsigned char c;
 
   while ((c = *str++) != 0)
-    r = r * 67 + c - 113;
+    {
+      if (index_version >= 5)
+	c = tolower (c);
+      r = r * 67 + c - 113;
+    }
 
   return r;
 }
@@ -1998,6 +2007,7 @@ find_slot_in_mapped_hash (struct mapped_index *index, const char *name,
   struct cleanup *back_to = make_cleanup (null_cleanup, 0);
   offset_type hash;
   offset_type slot, step;
+  int (*cmp) (const char *, const char *);
 
   if (current_language->la_language == language_cplus
       || current_language->la_language == language_java
@@ -2020,9 +2030,17 @@ find_slot_in_mapped_hash (struct mapped_index *index, const char *name,
 	}
     }
 
-  hash = mapped_index_string_hash (name);
+  /* Index version 4 did not support case insensitive searches.  But the
+     indexes for case insensitive languages are built in lowercase, therefore
+     simulate our NAME being searched is also lowercased.  */
+  hash = mapped_index_string_hash ((index->version == 4
+                                    && case_sensitivity == case_sensitive_off
+				    ? 5 : index->version),
+				   name);
+
   slot = hash & (index->symbol_table_slots - 1);
   step = ((hash * 17) & (index->symbol_table_slots - 1)) | 1;
+  cmp = (case_sensitivity == case_sensitive_on ? strcmp : strcasecmp);
 
   for (;;)
     {
@@ -2036,7 +2054,7 @@ find_slot_in_mapped_hash (struct mapped_index *index, const char *name,
 	}
 
       str = index->constant_pool + MAYBE_SWAP (index->symbol_table[i]);
-      if (!strcmp (name, str))
+      if (!cmp (name, str))
 	{
 	  *vec_out = (offset_type *) (index->constant_pool
 				      + MAYBE_SWAP (index->symbol_table[i + 1]));
@@ -2080,15 +2098,17 @@ dwarf2_read_index (struct objfile *objfile)
   /* Versions earlier than 3 emitted every copy of a psymbol.  This
      causes the index to behave very poorly for certain requests.  Version 3
      contained incomplete addrmap.  So, it seems better to just ignore such
-     indices.  */
+     indices.  Index version 4 uses a different hash function than index
+     version 5 and later.  */
   if (version < 4)
     return 0;
   /* Indexes with higher version than the one supported by GDB may be no
      longer backward compatible.  */
-  if (version > 4)
+  if (version > 5)
     return 0;
 
   map = OBSTACK_ZALLOC (&objfile->objfile_obstack, struct mapped_index);
+  map->version = version;
   map->total_size = dwarf2_per_objfile->gdb_index.size;
 
   metadata = (offset_type *) (addr + sizeof (offset_type));
@@ -15256,13 +15276,16 @@ struct strtab_entry
   const char *str;
 };
 
-/* Hash function for a strtab_entry.  */
+/* Hash function for a strtab_entry.
+
+   Function is used only during write_hash_table so no index format backward
+   compatibility is needed.  */
 
 static hashval_t
 hash_strtab_entry (const void *e)
 {
   const struct strtab_entry *entry = e;
-  return mapped_index_string_hash (entry->str);
+  return mapped_index_string_hash (INT_MAX, entry->str);
 }
 
 /* Equality function for a strtab_entry.  */
@@ -15400,12 +15423,15 @@ cleanup_mapped_symtab (void *p)
 }
 
 /* Find a slot in SYMTAB for the symbol NAME.  Returns a pointer to
-   the slot.  */
+   the slot.
+   
+   Function is used only during write_hash_table so no index format backward
+   compatibility is needed.  */
 
 static struct symtab_index_entry **
 find_slot (struct mapped_symtab *symtab, const char *name)
 {
-  offset_type index, step, hash = mapped_index_string_hash (name);
+  offset_type index, step, hash = mapped_index_string_hash (INT_MAX, name);
 
   index = hash & (symtab->size - 1);
   step = ((hash * 17) & (symtab->size - 1)) | 1;
@@ -15934,7 +15960,7 @@ write_psymtabs_to_index (struct objfile *objfile, const char *dir)
   total_len = size_of_contents;
 
   /* The version number.  */
-  val = MAYBE_SWAP (4);
+  val = MAYBE_SWAP (5);
   obstack_grow (&contents, &val, sizeof (val));
 
   /* The offset of the CU list from the start of the file.  */
--- a/gdb/minsyms.c
+++ b/gdb/minsyms.c
@@ -239,11 +239,16 @@ lookup_minimal_symbol (const char *name, const char *sfile,
 
 		  if (pass == 1)
 		    {
-		      match = strcmp (SYMBOL_LINKAGE_NAME (msymbol),
-				      modified_name) == 0;
+		      int (*cmp) (const char *, const char *);
+
+		      cmp = (case_sensitivity == case_sensitive_on
+		             ? strcmp : strcasecmp);
+		      match = cmp (SYMBOL_LINKAGE_NAME (msymbol),
+				   modified_name) == 0;
 		    }
 		  else
 		    {
+		      /* The function respects CASE_SENSITIVITY.  */
 		      match = SYMBOL_MATCHES_SEARCH_NAME (msymbol,
 							  modified_name);
 		    }
--- a/gdb/psymtab.c
+++ b/gdb/psymtab.c
@@ -691,8 +691,15 @@ lookup_partial_symbol (struct partial_symtab *pst, const char *name,
 	internal_error (__FILE__, __LINE__,
 			_("failed internal consistency check"));
 
-      while (top <= real_top
-	     && SYMBOL_MATCHES_SEARCH_NAME (*top, search_name))
+      /* For `case_sensitivity == case_sensitive_off' strcmp_iw_ordered will
+	 search more exactly than what matches SYMBOL_MATCHES_SEARCH_NAME.  */
+      while (top >= start && SYMBOL_MATCHES_SEARCH_NAME (*top, search_name))
+	top--;
+
+      /* Fixup to have a symbol which matches SYMBOL_MATCHES_SEARCH_NAME.  */
+      top++;
+
+      while (top <= real_top && SYMBOL_MATCHES_SEARCH_NAME (*top, search_name))
 	{
 	  if (symbol_matches_domain (SYMBOL_LANGUAGE (*top),
 				     SYMBOL_DOMAIN (*top), domain))
--- a/gdb/symtab.c
+++ b/gdb/symtab.c
@@ -1056,19 +1056,6 @@ lookup_symbol_in_language (const char *name, const struct block *block,
 	}
     }
 
-  if (case_sensitivity == case_sensitive_off)
-    {
-      char *copy;
-      int len, i;
-
-      len = strlen (name);
-      copy = (char *) alloca (len + 1);
-      for (i= 0; i < len; i++)
-        copy[i] = tolower (name[i]);
-      copy[len] = 0;
-      modified_name = copy;
-    }
-
   returnval = lookup_symbol_aux (modified_name, block, domain, lang,
 				 is_a_field_of_this);
   do_cleanups (cleanup);
@@ -3069,7 +3056,9 @@ search_symbols (char *regexp, enum search_domain kind,
 	    }
 	}
 
-      errcode = regcomp (&datum.preg, regexp, REG_NOSUB);
+      errcode = regcomp (&datum.preg, regexp,
+			 REG_NOSUB | (case_sensitivity == case_sensitive_off
+				      ? REG_ICASE : 0));
       if (errcode != 0)
 	{
 	  char *err = get_regcomp_error (errcode, &datum.preg);
@@ -3519,10 +3508,13 @@ completion_list_add_name (char *symname, char *sym_text, int sym_text_len,
 			  char *text, char *word)
 {
   int newsize;
+  int (*ncmp) (const char *, const char *, size_t);
+
+  ncmp = (case_sensitivity == case_sensitive_on ? strncmp : strncasecmp);
 
   /* Clip symbols that cannot match.  */
 
-  if (strncmp (symname, sym_text, sym_text_len) != 0)
+  if (ncmp (symname, sym_text, sym_text_len) != 0)
     {
       return;
     }
--- a/gdb/symtab.h
+++ b/gdb/symtab.h
@@ -1012,7 +1012,8 @@ extern unsigned int msymbol_hash (const char *);
    is only a GDB in-memory computed value with no external files compatibility
    requirements.  */
 
-#define SYMBOL_HASH_NEXT(hash, c) ((hash) * 67 + (c) - 113)
+#define SYMBOL_HASH_NEXT(hash, c) \
+  ((hash) * 67 + tolower ((unsigned char) (c)) - 113)
 
 extern struct objfile * msymbol_objfile (struct minimal_symbol *sym);
 
--- /dev/null
+++ b/gdb/testsuite/gdb.base/fortran-sym-case.c
@@ -0,0 +1,22 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+   Copyright 2011 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/>.  */
+
+int
+main (int argc, char **aRGv)
+{
+  return 0;
+}
--- /dev/null
+++ b/gdb/testsuite/gdb.base/fortran-sym-case.exp
@@ -0,0 +1,27 @@
+# Copyright (C) 2011 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/>.
+
+set testfile fortran-sym-case
+if { [prepare_for_testing ${testfile}.exp ${testfile}] } {
+    return -1
+}
+
+if ![runto_main] {
+    return -1
+}
+
+gdb_test "set language fortran" {Warning: the current language does not match this frame\.}
+
+gdb_test "frame" ", aRGv=.*"
--- /dev/null
+++ b/gdb/testsuite/gdb.dwarf2/dw2-case-insensitive-debug.S
@@ -0,0 +1,102 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+   Copyright 2011 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/>.  */
+
+	.section .debug_info
+.Lcu1_begin:
+	/* CU header */
+	.4byte	.Lcu1_end - .Lcu1_start		/* Length of Compilation Unit */
+.Lcu1_start:
+	.2byte	2				/* DWARF Version */
+	.4byte	.Labbrev1_begin			/* Offset into abbrev section */
+	.byte	4				/* Pointer size */
+
+	/* CU die */
+	.uleb128 1				/* Abbrev: DW_TAG_compile_unit */
+	.ascii	"file1.txt\0"			/* DW_AT_name */
+	.ascii	"GNU C 3.3.3\0"			/* DW_AT_producer */
+	.byte	8				/* DW_AT_language (DW_LANG_Fortran90) */
+	.4byte		FUNC_lang		/* DW_AT_low_pc */
+	.4byte		main			/* DW_AT_high_pc */
+
+	.uleb128	3			/* Abbrev: DW_TAG_subprogram */
+	.byte		1			/* DW_AT_external */
+	.ascii		"FUNC_lang\0"		/* DW_AT_name */
+	.4byte		FUNC_lang		/* DW_AT_low_pc */
+	.4byte		main			/* DW_AT_high_pc */
+	.byte		1			/* DW_AT_prototyped */
+	.4byte		.Ltype - .Lcu1_begin	/* DW_AT_type */
+
+.Ltype:
+	.uleb128 	0x5			/* Abbrev: DW_TAG_base_type */
+	.byte		0x4			/* DW_AT_byte_size */
+	.byte		0x5			/* DW_AT_encoding */
+	.ascii 		"foo\0"			/* DW_AT_name */
+
+	.byte		0			/* End of children of CU */
+.Lcu1_end:
+
+/* Abbrev table */
+	.section .debug_abbrev
+.Labbrev1_begin:
+	.uleb128	1			/* Abbrev code */
+	.uleb128	0x11			/* DW_TAG_compile_unit */
+	.byte		1			/* has_children */
+	.uleb128	0x3			/* DW_AT_name */
+	.uleb128	0x8			/* DW_FORM_string */
+	.uleb128	0x25			/* DW_AT_producer */
+	.uleb128	0x8			/* DW_FORM_string */
+	.uleb128	0x13			/* DW_AT_language */
+	.uleb128	0xb			/* DW_FORM_data1 */
+	.uleb128	0x11			/* DW_AT_low_pc */
+	.uleb128	0x1			/* DW_FORM_addr */
+	.uleb128	0x12			/* DW_AT_high_pc */
+	.uleb128	0x1			/* DW_FORM_addr */
+	.byte		0x0			/* Terminator */
+	.byte		0x0			/* Terminator */
+
+	.uleb128	3			/* Abbrev code */
+	.uleb128	0x2e			/* DW_TAG_subprogram */
+	.byte		0			/* has_children */
+	.uleb128	0x3f			/* DW_AT_external */
+	.uleb128	0xc			/* DW_FORM_flag */
+	.uleb128	0x3			/* DW_AT_name */
+	.uleb128	0x8			/* DW_FORM_string */
+	.uleb128	0x11			/* DW_AT_low_pc */
+	.uleb128	0x1			/* DW_FORM_addr */
+	.uleb128	0x12			/* DW_AT_high_pc */
+	.uleb128	0x1			/* DW_FORM_addr */
+	.uleb128	0x27			/* DW_AT_prototyped */
+	.uleb128	0xc			/* DW_FORM_flag */
+	.uleb128	0x49			/* DW_AT_type */
+	.uleb128	0x13			/* DW_FORM_ref4 */
+	.byte		0x0			/* Terminator */
+	.byte		0x0			/* Terminator */
+
+	.uleb128	0x5			/* Abbrev code */
+	.uleb128	0x24			/* DW_TAG_base_type */
+	.byte		0x0			/* DW_children_no */
+	.uleb128	0xb			/* DW_AT_byte_size */
+	.uleb128	0xb			/* DW_FORM_data1 */
+	.uleb128	0x3e			/* DW_AT_encoding */
+	.uleb128	0xb			/* DW_FORM_data1 */
+	.uleb128	0x3			/* DW_AT_name */
+	.uleb128	0x8			/* DW_FORM_string */
+	.byte		0x0			/* Terminator */
+	.byte		0x0			/* Terminator */
+
+	.byte		0x0			/* Terminator */
+	.byte		0x0			/* Terminator */
--- /dev/null
+++ b/gdb/testsuite/gdb.dwarf2/dw2-case-insensitive.c
@@ -0,0 +1,38 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+   Copyright 2011 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/>.  */
+
+/* Use DW_LANG_Fortran90 for case insensitive DWARF.  */
+
+void
+FUNC_lang (void)
+{
+}
+
+/* Symbol is present only in ELF .symtab.  */
+
+void
+FUNC_symtab (void)
+{
+}
+
+int
+main (void)
+{
+  FUNC_lang ();
+  FUNC_symtab ();
+  return 0;
+}
--- /dev/null
+++ b/gdb/testsuite/gdb.dwarf2/dw2-case-insensitive.exp
@@ -0,0 +1,49 @@
+# Copyright 2011 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/>.
+load_lib dwarf.exp
+
+# This test can only be run on targets which support DWARF-2 and use gas.
+if {![dwarf2_support]} {
+    return 0  
+}
+
+set testfile "dw2-case-insensitive"
+
+if { [prepare_for_testing ${testfile}.exp ${testfile} [list ${testfile}.c ${testfile}-debug.S] {nodebug}] } {
+    return -1
+}
+
+gdb_test "show case-sensitive" {Case sensitivity in name search is "auto; currently on"\.}
+
+gdb_test "info functions fUnC_lang" \
+	 "All functions matching regular expression \"fUnC_lang\":" \
+	 "regexp case-sensitive on"
+
+gdb_test "set case-sensitive off" {warning: the current case sensitivity setting does not match the language\.}
+
+gdb_test "info functions fUnC_lang" \
+	 "All functions matching regular expression \"fUnC_lang\":\[\r\n\]+File file1.txt:\r\nfoo FUNC_lang\\(void\\);" \
+	 "regexp case-sensitive off"
+
+gdb_test "p fuNC_lang" { = {foo \(void\)} 0x[0-9a-f]+ <FUNC_lang>}
+gdb_test "p fuNC_symtab" { = {<text variable, no debug info>} 0x[0-9a-f]+ <FUNC_symtab>}
+
+if {[gdb_breakpoint "fuNC_lang"] == 1} {
+    pass "setting breakpoint at fuNC_lang"
+}
+
+if {[gdb_breakpoint "fuNC_symtab"] == 1} {
+    pass "setting breakpoint at fuNC_symtab"
+}
--- a/gdb/utils.c
+++ b/gdb/utils.c
@@ -2974,10 +2974,12 @@ strcmp_iw (const char *string1, const char *string2)
 	{
 	  string2++;
 	}
-      if (*string1 != *string2)
-	{
-	  break;
-	}
+      if (case_sensitivity == case_sensitive_on && *string1 != *string2)
+	break;
+      if (case_sensitivity == case_sensitive_off
+	  && (tolower ((unsigned char) *string1)
+	      != tolower ((unsigned char) *string2)))
+	break;
       if (*string1 != '\0')
 	{
 	  string1++;
@@ -2998,6 +3000,10 @@ strcmp_iw (const char *string1, const char *string2)
    strcmp_iw(LIST_ELT, NAME), then the place to start looking is right
    where this function would put NAME.
 
+   This function must be neutral to the CASE_SENSITIVITY setting as the user
+   may choose it during later lookup.  Therefore this function always sorts
+   primarily case-insensitively and secondarily case-sensitively.
+
    Here are some examples of why using strcmp to sort is a bad idea:
 
    Whitespace example:
@@ -3023,8 +3029,10 @@ strcmp_iw (const char *string1, const char *string2)
 int
 strcmp_iw_ordered (const char *string1, const char *string2)
 {
-  /* Formatting stub.  */
-  if (1)
+  const char *saved_string1 = string1, *saved_string2 = string2;
+  enum case_sensitivity case_pass = case_sensitive_off;
+
+  for (;;)
     {
       /* C1 and C2 are valid only if *string1 != '\0' && *string2 != '\0'.
 	 Provide stub characters if we are already at the end of one of the
@@ -3038,8 +3046,17 @@ strcmp_iw_ordered (const char *string1, const char *string2)
 	  while (isspace (*string2))
 	    string2++;
 
+	  switch (case_pass)
+	  {
+	    case case_sensitive_off:
+	      c1 = tolower ((unsigned char) *string1);
+	      c2 = tolower ((unsigned char) *string2);
+	      break;
+	    case case_sensitive_on:
 	      c1 = *string1;
 	      c2 = *string2;
+	      break;
+	  }
 	  if (c1 != c2)
 	    break;
 
@@ -3057,7 +3074,7 @@ strcmp_iw_ordered (const char *string1, const char *string2)
 	     comparison in the cases where one of them is '\0' or '('.  */
 	case '\0':
 	  if (*string2 == '\0')
-	    return 0;
+	    break;
 	  else
 	    return -1;
 	case '(':
@@ -3068,9 +3085,22 @@ strcmp_iw_ordered (const char *string1, const char *string2)
 	default:
 	  if (*string2 == '\0' || *string2 == '(')
 	    return 1;
-	  else
-	    return c1 - c2;
+	  else if (c1 > c2)
+	    return 1;
+	  else if (c1 < c2)
+	    return -1;
+	  /* PASSTHRU */
 	}
+
+      if (case_pass == case_sensitive_on)
+	return 0;
+      
+      /* Otherwise the strings were equal in case insensitive way, make
+	 a more fine grained comparison in a case sensitive way.  */
+
+      case_pass = case_sensitive_on;
+      string1 = saved_string1;
+      string2 = saved_string2;
     }
 }
 


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]