Hello texinfo maintainers,

While working on reproducible live images [1], I noticed that the sort order in the file /usr/share/info/dir is unstable when nearly identical entries are added.

The order of the pairs 'diff', 'diff3' and 'who', 'whoami' was not guaranteed to be in dictionary order (i.e. shorter first)

Attached you find a diff based on the git checkout for version 7.1, which includes a test case that demonstrates the issue.

With kind regards,
Roland Clobus

[1] https://reproducible-builds.org/
diff --git a/install-info/install-info.c b/install-info/install-info.c
index 1377a5e6..0c736cd9 100644
--- a/install-info/install-info.c
+++ b/install-info/install-info.c
@@ -2822,7 +2822,11 @@ compare_entries_text (const void *p1, const void *p2)
     len2 = strlen (text2);
   else
     len2 = colon2 - text2;
-  return mbsncasecmp (text1, text2, len1 <= len2 ? len1 : len2);
+  int result = mbsncasecmp (text1, text2, len1 <= len2 ? len1 : len2);
+  if (result == 0) /* Identical start, the longer goes last */
+    return len1 <= len2 ? -1 : +1;
+  else
+    return result;
 }
 
 /* Insert ENTRY into the ADD_ENTRIES_BEFORE vector for line number LINE_NUMBER 
diff --git a/install-info/tests/Makefile.am b/install-info/tests/Makefile.am
index 278deaec..e9fb9069 100644
--- a/install-info/tests/Makefile.am
+++ b/install-info/tests/Makefile.am
@@ -21,7 +21,7 @@ ii-0036-test ii-0037-test ii-0038-test ii-0039-test ii-0040-test \
 ii-0041-test ii-0042-test ii-0043-test ii-0044-test ii-0045-test \
 ii-0046-test ii-0047-test ii-0048-test ii-0049-test ii-0050-test \
 ii-0051-test ii-0052-test ii-0053-test ii-0054-test ii-0055-test \
-ii-0056-test ii-0057-test ii-0058-test ii-0059-test
+ii-0056-test ii-0057-test ii-0058-test ii-0059-test ii-0060-test
 
 noinst_SCRIPTS=$(TESTS)
 
@@ -260,4 +260,8 @@ ii-0058-expected-dir-file \
 ii-0059-input-dir-file \
 ii-0059-input-info-file \
 ii-0059-expected-dir-file \
+\
+ii-0060-input-dir-file \
+ii-0060-input-info-file \
+ii-0060-expected-dir-file \
 README
diff --git a/install-info/tests/Makefile.in b/install-info/tests/Makefile.in
index d6399c21..5ba947c2 100644
--- a/install-info/tests/Makefile.in
+++ b/install-info/tests/Makefile.in
@@ -1789,7 +1789,7 @@ ii-0036-test ii-0037-test ii-0038-test ii-0039-test ii-0040-test \
 ii-0041-test ii-0042-test ii-0043-test ii-0044-test ii-0045-test \
 ii-0046-test ii-0047-test ii-0048-test ii-0049-test ii-0050-test \
 ii-0051-test ii-0052-test ii-0053-test ii-0054-test ii-0055-test \
-ii-0056-test ii-0057-test ii-0058-test ii-0059-test
+ii-0056-test ii-0057-test ii-0058-test ii-0059-test ii-0060-test
 
 noinst_SCRIPTS = $(TESTS)
 EXTRA_DIST = $(TESTS) \
@@ -2027,6 +2027,10 @@ ii-0058-expected-dir-file \
 ii-0059-input-dir-file \
 ii-0059-input-info-file \
 ii-0059-expected-dir-file \
+\
+ii-0060-input-dir-file \
+ii-0060-input-info-file \
+ii-0060-expected-dir-file \
 README
 
 all: all-am
@@ -2625,6 +2629,13 @@ ii-0059-test.log: ii-0059-test
 	--log-file $$b.log --trs-file $$b.trs \
 	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
 	"$$tst" $(AM_TESTS_FD_REDIRECT)
+ii-0060-test.log: ii-0060-test
+	@p='ii-0060-test'; \
+	b='ii-0060-test'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
 .test.log:
 	@p='$<'; \
 	$(am__set_b); \
diff --git a/install-info/tests/README b/install-info/tests/README
index 7724e464..c0457866 100644
--- a/install-info/tests/README
+++ b/install-info/tests/README
@@ -180,3 +180,5 @@ This file describes each of the numbered install-info tests.
       extra blank lines.
 0059: Deletion of section between two other sections leaves one
       blank line between the remaining sections.
+0060: Installing an Info file.  The Info file contains entries with the same
+      start, the longest entry should be listed last (dictionary sort).
diff --git a/install-info/tests/ii-0060-expected-dir-file b/install-info/tests/ii-0060-expected-dir-file
new file mode 100644
index 00000000..169ada43
--- /dev/null
+++ b/install-info/tests/ii-0060-expected-dir-file
@@ -0,0 +1,28 @@
+This is the directory file `dir' a.k.a. `DIR', which contains the
+  topmost node of the Info hierarchy.
+
+
+File: dir,	Node: Top,	This is the top of the INFO tree.
+
+This is the Info main menu (aka directory node).
+A few useful Info commands:
+
+  `q' quits;
+  `?' lists all Info commands;
+  `h' starts the Info tutorial;
+  `mTexinfo RET' visits the Texinfo manual, etc.
+
+* Menu:
+
+Animals
+* Aardvark: (aardvark).         Medium-sized African mammal.
+* Baboon: (baboon).             A monkey from Africa.
+* Chameleon: (chameleon).       A lizard from Africa.
+* Deer: (deer).                 Ruminent antlered mammal.
+* Emu: (emu).                   A flightless bird from Australia.
+* Fisher: (fisher).             A marten from North America.
+
+Diff programs
+* diff: (diffutils).            Compare 2 files.
+* diff2: (diffutils).           Imaginary tool. Intentionally after 'diff'
+* diff3: (diffutils).           Compare 3 files. Intentionally before 'diff'
diff --git a/install-info/tests/ii-0060-input-dir-file b/install-info/tests/ii-0060-input-dir-file
new file mode 100644
index 00000000..813b5486
--- /dev/null
+++ b/install-info/tests/ii-0060-input-dir-file
@@ -0,0 +1,23 @@
+This is the directory file `dir' a.k.a. `DIR', which contains the
+  topmost node of the Info hierarchy.
+
+
+File: dir,	Node: Top,	This is the top of the INFO tree.
+
+This is the Info main menu (aka directory node).
+A few useful Info commands:
+
+  `q' quits;
+  `?' lists all Info commands;
+  `h' starts the Info tutorial;
+  `mTexinfo RET' visits the Texinfo manual, etc.
+
+* Menu:
+
+Animals
+* Aardvark: (aardvark).         Medium-sized African mammal.
+* Baboon: (baboon).             A monkey from Africa.
+* Chameleon: (chameleon).       A lizard from Africa.
+* Deer: (deer).                 Ruminent antlered mammal.
+* Emu: (emu).                   A flightless bird from Australia.
+* Fisher: (fisher).             A marten from North America.
diff --git a/install-info/tests/ii-0060-input-info-file b/install-info/tests/ii-0060-input-info-file
new file mode 100644
index 00000000..3a88f463
--- /dev/null
+++ b/install-info/tests/ii-0060-input-info-file
@@ -0,0 +1,14 @@
+INFO-DIR-SECTION Diff programs
+START-INFO-DIR-ENTRY
+* diff3: (diffutils).                  Compare 3 files. Intentionally before 'diff'
+* diff: (diffutils).                   Compare 2 files.
+* diff2: (diffutils).                  Imaginary tool. Intentionally after 'diff'
+END-INFO-DIR-ENTRY
+
+File: gnu,  Node: Top,  Next: Top,  Up: (dir)
+
+Diff programs
+*************
+
+See diffutils.
+
diff --git a/install-info/tests/ii-0060-test b/install-info/tests/ii-0060-test
new file mode 100755
index 00000000..5f06aef0
--- /dev/null
+++ b/install-info/tests/ii-0060-test
@@ -0,0 +1,28 @@
+#!/bin/sh -x
+# This file is free software; as a special exception the author gives
+# unlimited permission to copy and/or distribute it, with or without
+# modifications, as long as this notice is preserved.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY, to the extent permitted by law; without even the
+# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+. ./defs || exit 1
+
+outputdirfile=`mktemp ii60-XXXXXXXX`
+cp ${testdir}/ii-0060-input-dir-file $outputdirfile
+if [ "x$?" != "x0" ]; then
+  exit 1
+fi
+
+${install_info} ${testdir}/ii-0060-input-info-file $outputdirfile
+retval=$?
+if [ "x$retval" != "x0" ]; then
+  exit $retval
+fi
+
+${diff} ${testdir}/ii-0060-expected-dir-file $outputdirfile
+retval=$?
+
+rm -f $outputdirfile
+exit $retval

Attachment: OpenPGP_signature.asc
Description: OpenPGP digital signature

Reply via email to