Author: rinrab
Date: Thu Apr  9 15:38:24 2026
New Revision: 1932928

Log:
svnbrowse: Sort all nodes in the list.

* subversion/svnbrowse/model.c
  (includes): Add private/svn_sorts_private.h for svn_sort__array().
  (compare_cstrings_lexically, compare_node_kind,
   sort_item_comparison_func): New functions.
  (svn_browse__state_create): Sort the list.

Modified:
   subversion/trunk/subversion/svnbrowse/model.c

Modified: subversion/trunk/subversion/svnbrowse/model.c
==============================================================================
--- subversion/trunk/subversion/svnbrowse/model.c       Thu Apr  9 15:29:54 
2026        (r1932927)
+++ subversion/trunk/subversion/svnbrowse/model.c       Thu Apr  9 15:38:24 
2026        (r1932928)
@@ -31,9 +31,59 @@
 #include "svn_error.h"
 
 #include "private/svn_client_private.h"
+#include "private/svn_sorts_private.h"
 
 #include "svnbrowse.h"
 
+/* similar to svn_sort_compare_items_lexically() */
+static int
+compare_cstrings_lexically(const char *a, const char *b)
+{
+  int alen = strlen(a);
+  int blen = strlen(b);
+  int len, val;
+
+  /* Compare bytes of a's key and b's key up to the common length. */
+  len = (alen < blen) ? alen : blen;
+  val = memcmp(a, b, len);
+
+  if (val != 0)
+    return val;
+
+  /* They match up until one of them ends; whichever is longer is greater. */
+  return (alen < blen) ? -1 : (alen > blen) ? 1 : 0;
+}
+
+/* sort comparator that puts directories before files */
+int static
+compare_node_kind(svn_node_kind_t a, svn_node_kind_t b)
+{
+  /* RA API should never return other node kinds */
+  SVN_ERR_ASSERT_NO_RETURN(a == svn_node_file || a == svn_node_dir);
+  SVN_ERR_ASSERT_NO_RETURN(b == svn_node_file || b == svn_node_dir);
+
+  /* so now we can do this safely */
+  return b - a;
+}
+
+/*
+ * 1. we want directories to be before files (compare_node_kind)
+ * 2. the nodes are sorted lexically (compare_cstrings_lexically)
+ */
+int static
+sort_item_comparison_func(const void *left, const void *right)
+{
+  /* don't worry about that... */
+  const svn_browse__item_t *a = *(const svn_browse__item_t **)left;
+  const svn_browse__item_t *b = *(const svn_browse__item_t **)right;
+
+  int val = compare_node_kind(a->dirent->kind, b->dirent->kind);
+  if (val != 0)
+    return val;
+
+  return compare_cstrings_lexically(a->name, b->name);
+}
+
 svn_error_t *
 svn_browse__state_create(svn_browse__state_t **state_p,
                          svn_ra_session_t *session,
@@ -68,6 +118,12 @@ svn_browse__state_create(svn_browse__sta
       APR_ARRAY_PUSH(state->list, svn_browse__item_t *) = item;
     }
 
+  /* libsvn_client:list.c, on the other hand, uses svn_sort__hash before coping
+   * items into an array. I prefer this approach instead because it's more
+   * pipeline-ish, I think. Firstly the targets are processed, secondly sorting
+   * rules are applied. */
+  svn_sort__array(state->list, sort_item_comparison_func);
+
   *state_p = state;
   return SVN_NO_ERROR;
 }

Reply via email to