No point having two copies of the same code.
Signed-off-by: NeilBrown <neil@brown.name>
### Triage
-- [ ] factor our list-sort code.
+- [X] factor our list-sort code.
- [X] when cx-b and default doc name is v.long, shift gets confused
- [ ] How to run shell command in "44" window??
- [X] In c-mode, if ) is at end of line then highlighting it causes the
static void get_stat(struct directory *dr safe, struct dir_ent *de safe);
-#define nm(le) (list_entry(le, struct dir_ent, lst)->name)
-
-/* Natural merge sort of the linked list of directory names */
-static void sort_list(struct list_head *lst safe)
+static char *key(struct list_head *le, const void *data)
{
- struct list_head *de[2];
- struct list_head *l;
-
- if (list_empty(lst))
- return;
- /* Convert to NULL terminated singly-linked list for sorting */
- lst->prev->next = safe_cast NULL;
-
- de[0] = lst->next;
- de[1] = NULL;
-
- do {
- struct list_head ** safe dep[2];
- struct list_head *d[2];
- int curr = 0;
- char *prev = "";
- int next = 0;
-
- dep[0] = &de[0];
- dep[1] = &de[1];
- d[0] = de[0];
- d[1] = de[1];
-
- /* d[0] and d[1] are two lists to be merged and split.
- * The results will be put in de[0] and de[1].
- * dep[0] and dep[1] are end pointers to de[0] and de[1] so far.
- *
- * Take least of d[0] and d[1].
- * If it is larger than prev, add to
- * dep[curr], else swap curr then add
- */
- while (d[0] || d[1]) {
- if (d[next] == NULL ||
- (d[1-next] != NULL &&
- !((strcmp(prev, nm(d[1-next])) <= 0)
- ^(strcmp(nm(d[1-next]), nm(d[next])) <= 0)
- ^(strcmp(nm(d[next]), prev) <= 0)))
- )
- next = 1 - next;
-
- if (!d[next])
- break;
- if (strcmp(nm(d[next]), prev) < 0)
- curr = 1 - curr;
- prev = nm(d[next]);
- *dep[curr] = d[next];
- dep[curr] = &d[next]->next;
- d[next] = d[next]->next;
- }
- *dep[0] = NULL;
- *dep[1] = NULL;
- } while (de[0] && de[1]);
-
- /* Now re-assemble the doublely-linked list */
- if (de[0])
- lst->next = de[0];
- else
- lst->next = safe_cast de[1];
- l = lst;
-
- while ((void*)l->next) {
- l->next->prev = l;
- l = l->next;
- }
- l->next = lst;
- lst->prev = l;
+ if (le == NULL)
+ return NULL;
+ return list_entry(le, struct dir_ent, lst)->name;
}
static bool add_ent(struct list_head *lst safe, struct dirent *de safe)
return;
while ((res = readdir(dir)) != NULL)
add_ent(lst, res);
- sort_list(lst);
+ sort_list(lst, key, NULL);
closedir(dir);
}
return 1;
}
-static char *key(struct list_head *le, const char *keyattr safe)
+static char *key(struct list_head *le, const void *data)
{
+ const char *keyattr = data;
struct elmnt *e;
char *ret;
- if (le == NULL)
+ if (le == NULL || keyattr == NULL)
return NULL;
e = container_of(le, struct elmnt, list);
ret = attr_find(e->attrs, keyattr);
return ret ?: "";
}
-static void sort_list(struct list_head *lst safe, const char *keyattr safe)
-{
- struct list_head *de[2];
- struct list_head *l;
-
- if (list_empty(lst))
- return;
- /* Convert to NULL terminated singly-linked list for sorting */
- lst->prev->next = safe_cast NULL;
-
- de[0] = lst->next;
- de[1] = NULL;
-
- do {
- struct list_head ** safe dep[2];
- struct list_head *d[2];
- int curr = 0;
- char *prev = "";
- int next = 0;
-
- dep[0] = &de[0];
- dep[1] = &de[1];
- d[0] = de[0];
- d[1] = de[1];
-
- /* d[0] and d[1] are two lists to be merged and split.
- * The results will be put in de[0] and de[1].
- * dep[0] and dep[1] are end pointers to de[0] and de[1] so far.
- *
- * Take least of d[0] and d[1].
- * If it is larger than prev, add to
- * dep[curr], else swap curr then add
- */
- while (d[0] || d[1]) {
- char *kn = key(d[next], keyattr);
- char *kp = key(d[1-next], keyattr);
- if (kn == NULL ||
- (kp != NULL &&
- !((strcmp(prev, kp) <= 0)
- ^(strcmp(kp, kn) <= 0)
- ^(strcmp(kn, prev) <= 0)))
- ) {
- char *t = kn;
- kn = kp;
- kp = t;
- next = 1 - next;
- }
-
- if (!d[next] || !kn)
- break;
- if (strcmp(kn, prev) < 0)
- curr = 1 - curr;
- prev = kn;
- *dep[curr] = d[next];
- dep[curr] = &d[next]->next;
- d[next] = d[next]->next;
- }
- *dep[0] = NULL;
- *dep[1] = NULL;
- } while (de[0] && de[1]);
-
- /* Now re-assemble the doublely-linked list */
- if (de[0])
- lst->next = de[0];
- else
- lst->next = safe_cast de[1];
- l = lst;
-
- while ((void*)l->next) {
- l->next->prev = l;
- l = l->next;
- }
- l->next = lst;
- lst->prev = l;
-}
-
DEF_CMD(list_sort)
{
struct list *l = &ci->home->doc_data;
m->ref.p = NULL;
m->ref.i = 0;
}
- sort_list(&l->content, ci->str);
+ sort_list(&l->content, key, ci->str);
return 1;
}
TLIST_TYPE(&pos->member) != (head_type); \
pos = tlist_prev_entry(pos, member))
+/* Natural merge sort of the linked list */
+static inline void sort_list(struct list_head *lst safe,
+ char * (*key)(struct list_head *le, const void *data),
+ const void *data)
+{
+ struct list_head *de[2];
+ struct list_head *l;
+
+ if (list_empty(lst))
+ return;
+ /* Convert to NULL terminated singly-linked list for sorting */
+ lst->prev->next = safe_cast NULL;
+
+ de[0] = lst->next;
+ de[1] = NULL;
+
+ do {
+ struct list_head ** safe dep[2];
+ struct list_head *d[2];
+ int curr = 0;
+ char *prev = "";
+ int next = 0;
+
+ dep[0] = &de[0];
+ dep[1] = &de[1];
+ d[0] = de[0];
+ d[1] = de[1];
+
+ /* d[0] and d[1] are two lists to be merged and split.
+ * The results will be put in de[0] and de[1].
+ * dep[0] and dep[1] are end pointers to de[0] and de[1] so far.
+ *
+ * Take least of d[0] and d[1].
+ * If it is larger than prev, add to
+ * dep[curr], else swap curr then add
+ */
+ while (d[0] || d[1]) {
+ char *kn = key(d[next], data);
+ char *kp = key(d[1-next], data);
+ if (kn == NULL ||
+ (kp != NULL &&
+ !((strcmp(prev, kp) <= 0)
+ ^(strcmp(kp, kn) <= 0)
+ ^(strcmp(kn, prev) <= 0)))
+ ) {
+ char *t = kn;
+ kn = kp;
+ kp = t;
+ next = 1 - next;
+ }
+
+ if (!d[next] || !kn)
+ break;
+ if (strcmp(kn, prev) < 0)
+ curr = 1 - curr;
+ prev = kn;
+ *dep[curr] = d[next];
+ dep[curr] = &d[next]->next;
+ d[next] = d[next]->next;
+ }
+ *dep[0] = NULL;
+ *dep[1] = NULL;
+ } while (de[0] && de[1]);
+
+ /* Now re-assemble the doublely-linked list */
+ if (de[0])
+ lst->next = de[0];
+ else
+ lst->next = safe_cast de[1];
+ l = lst;
+
+ while ((void*)l->next) {
+ l->next->prev = l;
+ l = l->next;
+ }
+ l->next = lst;
+ lst->prev = l;
+}
#endif /* __LIST_H__ */