mirror of
https://github.com/tmux/tmux.git
synced 2026-02-15 18:49:18 +00:00
Break sorting out into a common file so formats and modes use the same
code. Also add -O for sorting to the list commands. From Dane Jensen in GitHub issue 4813.
This commit is contained in:
536
sort.c
Normal file
536
sort.c
Normal file
@@ -0,0 +1,536 @@
|
||||
/* $OpenBSD$ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2026 Dane Jensen <dhcjensen@gmail.com>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
|
||||
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "tmux.h"
|
||||
|
||||
static struct sort_criteria *sort_criteria;
|
||||
|
||||
static void
|
||||
sort_qsort(void *l, u_int len, u_int size, int (*cmp)(const void *, const void *),
|
||||
struct sort_criteria *sort_crit)
|
||||
{
|
||||
u_int i;
|
||||
void *tmp, **ll;
|
||||
|
||||
if (sort_crit->order == SORT_END)
|
||||
return;
|
||||
|
||||
if (sort_crit->order == SORT_ORDER) {
|
||||
if (sort_crit->reversed) {
|
||||
ll = l;
|
||||
for (i = 0; i < len / 2; i++) {
|
||||
tmp = ll[i];
|
||||
ll[i] = ll[len - 1 - i];
|
||||
ll[len - 1 - i] = tmp;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
sort_criteria = sort_crit;
|
||||
qsort(l, len, size, cmp);
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
sort_buffer_cmp(const void *a0, const void *b0)
|
||||
{
|
||||
struct sort_criteria *sort_crit = sort_criteria;
|
||||
const struct paste_buffer *const *a = a0;
|
||||
const struct paste_buffer *const *b = b0;
|
||||
const struct paste_buffer *pa = *a;
|
||||
const struct paste_buffer *pb = *b;
|
||||
int result = 0;
|
||||
|
||||
switch (sort_crit->order) {
|
||||
case SORT_NAME:
|
||||
result = strcmp(pa->name, pb->name);
|
||||
break;
|
||||
case SORT_CREATION:
|
||||
result = pa->order - pb->order;
|
||||
break;
|
||||
case SORT_SIZE:
|
||||
result = pa->size - pb->size;
|
||||
break;
|
||||
case SORT_ACTIVITY:
|
||||
case SORT_INDEX:
|
||||
case SORT_ORDER:
|
||||
case SORT_END:
|
||||
break;
|
||||
}
|
||||
|
||||
if (result == 0)
|
||||
result = strcmp(pa->name, pb->name);
|
||||
|
||||
if (sort_crit->reversed)
|
||||
result = -result;
|
||||
return (result);
|
||||
}
|
||||
|
||||
static int
|
||||
sort_client_cmp(const void *a0, const void *b0)
|
||||
{
|
||||
struct sort_criteria *sort_crit = sort_criteria;
|
||||
const struct client *const *a = a0;
|
||||
const struct client *const *b = b0;
|
||||
const struct client *ca = *a;
|
||||
const struct client *cb = *b;
|
||||
int result = 0;
|
||||
|
||||
switch (sort_crit->order) {
|
||||
case SORT_NAME:
|
||||
result = strcmp(ca->name, cb->name);
|
||||
break;
|
||||
case SORT_SIZE:
|
||||
result = ca->tty.sx - cb->tty.sx;
|
||||
if (result == 0)
|
||||
result = ca->tty.sy - cb->tty.sy;
|
||||
break;
|
||||
case SORT_CREATION:
|
||||
if (timercmp(&ca->creation_time, &cb->creation_time, >))
|
||||
result = 1;
|
||||
else if (timercmp(&ca->creation_time, &cb->creation_time, <))
|
||||
result = -1;
|
||||
break;
|
||||
case SORT_ACTIVITY:
|
||||
if (timercmp(&ca->activity_time, &cb->activity_time, >))
|
||||
result = -1;
|
||||
else if (timercmp(&ca->activity_time, &cb->activity_time, <))
|
||||
result = 1;
|
||||
break;
|
||||
case SORT_INDEX:
|
||||
case SORT_ORDER:
|
||||
case SORT_END:
|
||||
break;
|
||||
}
|
||||
|
||||
if (result == 0)
|
||||
result = strcmp(ca->name, cb->name);
|
||||
|
||||
if (sort_crit->reversed)
|
||||
result = -result;
|
||||
return (result);
|
||||
}
|
||||
|
||||
static int
|
||||
sort_session_cmp(const void *a0, const void *b0)
|
||||
{
|
||||
struct sort_criteria *sort_crit = sort_criteria;
|
||||
const struct session *const *a = a0;
|
||||
const struct session *const *b = b0;
|
||||
const struct session *sa = *a;
|
||||
const struct session *sb = *b;
|
||||
int result = 0;
|
||||
|
||||
switch (sort_crit->order) {
|
||||
case SORT_INDEX:
|
||||
result = sa->id - sb->id;
|
||||
break;
|
||||
case SORT_CREATION:
|
||||
if (timercmp(&sa->creation_time, &sb->creation_time, >)) {
|
||||
result = 1;
|
||||
break;
|
||||
}
|
||||
if (timercmp(&sa->creation_time, &sb->creation_time, <)) {
|
||||
result = -1;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case SORT_ACTIVITY:
|
||||
if (timercmp(&sa->activity_time, &sb->activity_time, >)) {
|
||||
result = -1;
|
||||
break;
|
||||
}
|
||||
if (timercmp(&sa->activity_time, &sb->activity_time, <)) {
|
||||
result = 1;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case SORT_NAME:
|
||||
result = strcmp(sa->name, sb->name);
|
||||
break;
|
||||
case SORT_ORDER:
|
||||
case SORT_SIZE:
|
||||
case SORT_END:
|
||||
break;
|
||||
}
|
||||
|
||||
if (result == 0)
|
||||
result = strcmp(sa->name, sb->name);
|
||||
|
||||
if (sort_crit->reversed)
|
||||
result = -result;
|
||||
return (result);
|
||||
}
|
||||
|
||||
static int
|
||||
sort_pane_cmp(const void *a0, const void *b0)
|
||||
{
|
||||
struct sort_criteria *sort_crit = sort_criteria;
|
||||
struct window_pane *a = *(struct window_pane **)a0;
|
||||
struct window_pane *b = *(struct window_pane **)b0;
|
||||
int result = 0;
|
||||
u_int ai, bi;
|
||||
|
||||
switch (sort_crit->order) {
|
||||
case SORT_ACTIVITY:
|
||||
result = a->active_point - b->active_point;
|
||||
break;
|
||||
case SORT_CREATION:
|
||||
result = a->id - b->id;
|
||||
break;
|
||||
case SORT_INDEX:
|
||||
case SORT_NAME:
|
||||
case SORT_ORDER:
|
||||
case SORT_SIZE:
|
||||
case SORT_END:
|
||||
break;
|
||||
}
|
||||
if (result == 0) {
|
||||
/*
|
||||
* Panes don't have names, so use number order for any other
|
||||
* sort field.
|
||||
*/
|
||||
window_pane_index(a, &ai);
|
||||
window_pane_index(b, &bi);
|
||||
result = ai - bi;
|
||||
}
|
||||
|
||||
if (sort_crit->reversed)
|
||||
result = -result;
|
||||
return (result);
|
||||
}
|
||||
|
||||
static int
|
||||
sort_winlink_cmp(const void *a0, const void *b0)
|
||||
{
|
||||
struct sort_criteria *sort_crit = sort_criteria;
|
||||
const struct winlink *const *a = a0;
|
||||
const struct winlink *const *b = b0;
|
||||
const struct winlink *wla = *a;
|
||||
const struct winlink *wlb = *b;
|
||||
struct window *wa = wla->window;
|
||||
struct window *wb = wlb->window;
|
||||
int result = 0;
|
||||
|
||||
switch (sort_crit->order) {
|
||||
case SORT_INDEX:
|
||||
result = wla->idx - wlb->idx;
|
||||
break;
|
||||
case SORT_ACTIVITY:
|
||||
if (timercmp(&wa->activity_time, &wb->activity_time, >)) {
|
||||
result = -1;
|
||||
break;
|
||||
}
|
||||
if (timercmp(&wa->activity_time, &wb->activity_time, <)) {
|
||||
result = 1;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case SORT_NAME:
|
||||
result = strcmp(wa->name, wb->name);
|
||||
break;
|
||||
case SORT_CREATION:
|
||||
case SORT_ORDER:
|
||||
case SORT_SIZE:
|
||||
case SORT_END:
|
||||
break;
|
||||
}
|
||||
|
||||
if (result == 0)
|
||||
result = strcmp(wa->name, wb->name);
|
||||
|
||||
if (sort_crit->reversed)
|
||||
result = -result;
|
||||
return (result);
|
||||
}
|
||||
|
||||
void
|
||||
sort_next_order(struct sort_criteria *sort_crit)
|
||||
{
|
||||
u_int i;
|
||||
|
||||
if (sort_crit->order_seq == NULL)
|
||||
return;
|
||||
for (i = 0; sort_crit->order_seq[i] != SORT_END; i++) {
|
||||
if (sort_crit->order == sort_crit->order_seq[i])
|
||||
break;
|
||||
}
|
||||
|
||||
if (sort_crit->order_seq[i] == SORT_END)
|
||||
i = 0;
|
||||
else {
|
||||
i++;
|
||||
if (sort_crit->order_seq[i] == SORT_END)
|
||||
i = 0;
|
||||
}
|
||||
sort_crit->order = sort_crit->order_seq[i];
|
||||
}
|
||||
|
||||
enum sort_order
|
||||
sort_order_from_string(const char* order)
|
||||
{
|
||||
if (order != NULL) {
|
||||
if (strcasecmp(order, "activity") == 0)
|
||||
return (SORT_ACTIVITY);
|
||||
if (strcasecmp(order, "creation") == 0)
|
||||
return (SORT_CREATION);
|
||||
if (strcasecmp(order, "index") == 0)
|
||||
return (SORT_INDEX);
|
||||
if (strcasecmp(order, "name") == 0)
|
||||
return (SORT_NAME);
|
||||
if (strcasecmp(order, "order") == 0)
|
||||
return (SORT_ORDER);
|
||||
if (strcasecmp(order, "size") == 0)
|
||||
return (SORT_SIZE);
|
||||
}
|
||||
return (SORT_END);
|
||||
}
|
||||
|
||||
const char *
|
||||
sort_order_to_string(enum sort_order order)
|
||||
{
|
||||
if (order == SORT_ACTIVITY)
|
||||
return "activity";
|
||||
if (order == SORT_CREATION)
|
||||
return "creation";
|
||||
if (order == SORT_INDEX)
|
||||
return "index";
|
||||
if (order == SORT_NAME)
|
||||
return "name";
|
||||
if (order == SORT_ORDER)
|
||||
return "order";
|
||||
if (order == SORT_SIZE)
|
||||
return "size";
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
int
|
||||
sort_would_window_tree_swap(struct sort_criteria *sort_crit,
|
||||
struct winlink *wla, struct winlink *wlb)
|
||||
{
|
||||
if (sort_crit->order == SORT_INDEX)
|
||||
return (0);
|
||||
sort_criteria = sort_crit;
|
||||
return (sort_winlink_cmp(&wla, &wlb) != 0);
|
||||
}
|
||||
|
||||
struct paste_buffer **
|
||||
sort_get_buffers(u_int *n, struct sort_criteria *sort_crit)
|
||||
{
|
||||
struct paste_buffer *pb = NULL;
|
||||
u_int i;
|
||||
static struct paste_buffer **l = NULL;
|
||||
static u_int lsz = 0;
|
||||
|
||||
i = 0;
|
||||
while ((pb = paste_walk(pb)) != NULL) {
|
||||
if (lsz <= i) {
|
||||
lsz += 100;
|
||||
l = xreallocarray(l, lsz, sizeof *l);
|
||||
}
|
||||
l[i++] = pb;
|
||||
}
|
||||
|
||||
sort_qsort(l, i, sizeof *l, sort_buffer_cmp, sort_crit);
|
||||
*n = i;
|
||||
|
||||
return (l);
|
||||
}
|
||||
|
||||
struct client **
|
||||
sort_get_clients(u_int *n, struct sort_criteria *sort_crit)
|
||||
{
|
||||
struct client *c;
|
||||
u_int i;
|
||||
static struct client **l = NULL;
|
||||
static u_int lsz = 0;
|
||||
|
||||
i = 0;
|
||||
TAILQ_FOREACH(c, &clients, entry) {
|
||||
if (lsz <= i) {
|
||||
lsz += 100;
|
||||
l = xreallocarray(l, lsz, sizeof *l);
|
||||
}
|
||||
l[i++] = c;
|
||||
}
|
||||
|
||||
sort_qsort(l, i, sizeof *l, sort_client_cmp, sort_crit);
|
||||
*n = i;
|
||||
|
||||
return (l);
|
||||
}
|
||||
|
||||
struct session **
|
||||
sort_get_sessions(u_int *n, struct sort_criteria *sort_crit)
|
||||
{
|
||||
struct session *s;
|
||||
u_int i;
|
||||
static struct session **l = NULL;
|
||||
static u_int lsz = 0;
|
||||
|
||||
i = 0;
|
||||
RB_FOREACH(s, sessions, &sessions) {
|
||||
if (lsz <= i) {
|
||||
lsz += 100;
|
||||
l = xreallocarray(l, lsz, sizeof *l);
|
||||
}
|
||||
l[i++] = s;
|
||||
}
|
||||
|
||||
sort_qsort(l, i, sizeof *l, sort_session_cmp, sort_crit);
|
||||
*n = i;
|
||||
|
||||
return (l);
|
||||
}
|
||||
|
||||
struct window_pane **
|
||||
sort_get_panes(u_int *n, struct sort_criteria *sort_crit)
|
||||
{
|
||||
struct session *s;
|
||||
struct winlink *wl;
|
||||
struct window *w;
|
||||
struct window_pane *wp;
|
||||
u_int i;
|
||||
static struct window_pane **l = NULL;
|
||||
static u_int lsz = 0;
|
||||
|
||||
i = 0;
|
||||
RB_FOREACH(s, sessions, &sessions) {
|
||||
RB_FOREACH(wl, winlinks, &s->windows) {
|
||||
w = wl->window;
|
||||
TAILQ_FOREACH(wp, &w->panes, entry) {
|
||||
if (lsz <= i) {
|
||||
lsz += 100;
|
||||
l = xreallocarray(l, lsz, sizeof *l);
|
||||
}
|
||||
l[i++] = wp;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sort_qsort(l, i, sizeof *l, sort_pane_cmp, sort_crit);
|
||||
*n = i;
|
||||
|
||||
return (l);
|
||||
}
|
||||
|
||||
struct window_pane **
|
||||
sort_get_panes_session(struct session *s, u_int *n,
|
||||
struct sort_criteria *sort_crit)
|
||||
{
|
||||
struct winlink *wl = NULL;
|
||||
struct window *w = NULL;
|
||||
struct window_pane *wp = NULL;
|
||||
u_int i;
|
||||
static struct window_pane **l = NULL;
|
||||
static u_int lsz = 0;
|
||||
|
||||
i = 0;
|
||||
RB_FOREACH(wl, winlinks, &s->windows) {
|
||||
TAILQ_FOREACH(wp, &w->panes, entry) {
|
||||
if (lsz <= i) {
|
||||
lsz += 100;
|
||||
l = xreallocarray(l, lsz, sizeof *l);
|
||||
}
|
||||
l[i++] = wp;
|
||||
}
|
||||
}
|
||||
|
||||
sort_qsort(l, i, sizeof *l, sort_pane_cmp, sort_crit);
|
||||
*n = i;
|
||||
|
||||
return (l);
|
||||
}
|
||||
|
||||
struct window_pane **
|
||||
sort_get_panes_window(struct window *w, u_int *n,
|
||||
struct sort_criteria *sort_crit)
|
||||
{
|
||||
struct window_pane *wp;
|
||||
u_int i;
|
||||
static struct window_pane **l = NULL;
|
||||
static u_int lsz = 0;
|
||||
|
||||
i = 0;
|
||||
TAILQ_FOREACH(wp, &w->panes, entry) {
|
||||
if (lsz <= i) {
|
||||
lsz += 100;
|
||||
l = xreallocarray(l, lsz, sizeof *l);
|
||||
}
|
||||
l[i++] = wp;
|
||||
}
|
||||
|
||||
sort_qsort(l, i, sizeof *l, sort_pane_cmp, sort_crit);
|
||||
*n = i;
|
||||
|
||||
return (l);
|
||||
}
|
||||
|
||||
struct winlink **
|
||||
sort_get_winlinks(u_int *n, struct sort_criteria *sort_crit)
|
||||
{
|
||||
struct session *s;
|
||||
struct winlink *wl;
|
||||
u_int i;
|
||||
static struct winlink **l = NULL;
|
||||
static u_int lsz = 0;
|
||||
|
||||
i = 0;
|
||||
RB_FOREACH(s, sessions, &sessions) {
|
||||
RB_FOREACH(wl, winlinks, &s->windows) {
|
||||
if (lsz <= i) {
|
||||
lsz += 100;
|
||||
l = xreallocarray(l, lsz, sizeof *l);
|
||||
}
|
||||
l[i++] = wl;
|
||||
}
|
||||
}
|
||||
|
||||
sort_qsort(l, i, sizeof *l, sort_winlink_cmp, sort_crit);
|
||||
*n = i;
|
||||
|
||||
return (l);
|
||||
}
|
||||
|
||||
struct winlink **
|
||||
sort_get_winlinks_session(struct session *s, u_int *n,
|
||||
struct sort_criteria *sort_crit)
|
||||
{
|
||||
struct winlink *wl;
|
||||
u_int i;
|
||||
static struct winlink **l = NULL;
|
||||
static u_int lsz = 0;
|
||||
|
||||
i = 0;
|
||||
RB_FOREACH(wl, winlinks, &s->windows) {
|
||||
if (lsz <= i) {
|
||||
lsz += 100;
|
||||
l = xreallocarray(l, lsz, sizeof *l);
|
||||
}
|
||||
l[i++] = wl;
|
||||
}
|
||||
|
||||
sort_qsort(l, i, sizeof *l, sort_winlink_cmp, sort_crit);
|
||||
*n = i;
|
||||
|
||||
return (l);
|
||||
}
|
||||
Reference in New Issue
Block a user