+ struct name *first_list;
+ struct name *second_list;
+ int first_length;
+ int second_length;
+ struct name *result;
+ struct name **merge_point;
+ struct name *cursor;
+ int counter;
+
+# define SUCCESSOR(name) ((name)->next)
+
+ if (length == 1)
+ return list;
+
+ if (length == 2)
+ {
+ if ((*compare) (list, SUCCESSOR (list)) > 0)
+ {
+ result = SUCCESSOR (list);
+ SUCCESSOR (result) = list;
+ SUCCESSOR (list) = 0;
+ return result;
+ }
+ return list;
+ }
+
+ first_list = list;
+ first_length = (length + 1) / 2;
+ second_length = length / 2;
+ for (cursor = list, counter = first_length - 1;
+ counter;
+ cursor = SUCCESSOR (cursor), counter--)
+ continue;
+ second_list = SUCCESSOR (cursor);
+ SUCCESSOR (cursor) = 0;
+
+ first_list = merge_sort (first_list, first_length, compare);
+ second_list = merge_sort (second_list, second_length, compare);
+
+ merge_point = &result;
+ while (first_list && second_list)
+ if ((*compare) (first_list, second_list) < 0)
+ {
+ cursor = SUCCESSOR (first_list);
+ *merge_point = first_list;
+ merge_point = &SUCCESSOR (first_list);
+ first_list = cursor;
+ }
+ else
+ {
+ cursor = SUCCESSOR (second_list);
+ *merge_point = second_list;
+ merge_point = &SUCCESSOR (second_list);
+ second_list = cursor;
+ }
+ if (first_list)
+ *merge_point = first_list;
+ else
+ *merge_point = second_list;
+
+ return result;
+
+#undef SUCCESSOR
+}
+
+/* A comparison function for sorting names. Put found names last;
+ break ties by string comparison. */
+
+static int
+compare_names (struct name const *n1, struct name const *n2)
+{
+ int found_diff = n2->found - n1->found;
+ return found_diff ? found_diff : strcmp (n1->name, n2->name);
+}
+\f
+/* Add all the dirs under NAME, which names a directory, to the namelist.
+ DIRSIZE is the size of the directory, or -1 if not known.
+ If any of the files is a directory, recurse on the subdirectory.
+ DEVICE is the device not to leave, if the -l option is specified. */
+
+static void
+add_hierarchy_to_namelist (struct name *name, off_t dirsize, dev_t device)
+{
+ char *path = name->name;
+ char *buffer = get_directory_contents (path, dirsize, device);
+
+ if (! buffer)
+ name->dir_contents = "\0\0\0\0";
+ else
+ {
+ size_t name_length = name->length;
+ size_t allocated_length = (name_length >= NAME_FIELD_SIZE
+ ? name_length + NAME_FIELD_SIZE
+ : NAME_FIELD_SIZE);
+ char *name_buffer = xmalloc (allocated_length + 1);
+ /* FIXME: + 2 above? */
+ char *string;
+ size_t string_length;
+ int change_dir = name->change_dir;
+
+ name->dir_contents = buffer;
+ strcpy (name_buffer, path);
+ if (name_buffer[name_length - 1] != '/')
+ {
+ name_buffer[name_length++] = '/';
+ name_buffer[name_length] = '\0';
+ }
+
+ for (string = buffer; *string; string += string_length + 1)
+ {
+ string_length = strlen (string);
+ if (*string == 'D')
+ {
+ if (name_length + string_length >= allocated_length)
+ {
+ while (name_length + string_length >= allocated_length)
+ allocated_length += NAME_FIELD_SIZE;
+ name_buffer = xrealloc (name_buffer, allocated_length + 1);
+ }
+ strcpy (name_buffer + name_length, string + 1);
+ add_hierarchy_to_namelist (addname (name_buffer, change_dir),
+ -1, device);
+ }
+ }
+
+ free (name_buffer);
+ }