Coverage Report

Created: 2026-10-17 06:19

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/tmux/sort.c
Line
Count
Source
1
/* $OpenBSD: sort.c,v 1.12 2026/09/28 10:42:01 nicm Exp $ */
2
3
/*
4
 * Copyright (c) 2026 Dane Jensen <dhcjensen@gmail.com>
5
 *
6
 * Permission to use, copy, modify, and distribute this software for any
7
 * purpose with or without fee is hereby granted, provided that the above
8
 * copyright notice and this permission notice appear in all copies.
9
 *
10
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14
 * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
15
 * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
16
 * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17
 */
18
19
#include <sys/types.h>
20
21
#include <stdlib.h>
22
#include <string.h>
23
24
#include "tmux.h"
25
26
static struct sort_criteria *sort_criteria;
27
28
static int
29
sort_number_cmp(unsigned long long a, unsigned long long b)
30
0
{
31
0
  if (a < b)
32
0
    return (-1);
33
0
  if (a > b)
34
0
    return (1);
35
0
  return (0);
36
0
}
37
38
static void
39
sort_qsort(void *l, u_int len, u_int size, int (*cmp)(const void *,
40
    const void *), struct sort_criteria *sort_crit)
41
19.1k
{
42
19.1k
  u_int  i;
43
19.1k
  void  *tmp, **ll;
44
45
19.1k
  if (len < 2 || sort_crit->order == SORT_END)
46
19.1k
    return;
47
48
0
  if (sort_crit->order == SORT_ORDER) {
49
0
    if (sort_crit->reversed) {
50
0
      ll = l;
51
0
      for (i = 0; i < len / 2; i++) {
52
0
        tmp = ll[i];
53
0
        ll[i] = ll[len - 1 - i];
54
0
        ll[len - 1 - i] = tmp;
55
0
      }
56
0
    }
57
0
  } else {
58
0
    sort_criteria = sort_crit;
59
0
    qsort(l, len, size, cmp);
60
0
  }
61
0
}
62
63
static int
64
sort_buffer_cmp(const void *a0, const void *b0)
65
0
{
66
0
  struct sort_criteria      *sort_crit = sort_criteria;
67
0
  const struct paste_buffer *const  *a = a0;
68
0
  const struct paste_buffer *const  *b = b0;
69
0
  const struct paste_buffer   *pa = *a;
70
0
  const struct paste_buffer   *pb = *b;
71
0
  int          result = 0;
72
73
0
  switch (sort_crit->order) {
74
0
  case SORT_NAME:
75
0
    result = strcmp(pa->name, pb->name);
76
0
    break;
77
0
  case SORT_CREATION:
78
0
    if (pa->order > pb->order)
79
0
      result = -1;
80
0
    else if (pa->order < pb->order)
81
0
      result = 1;
82
0
    else
83
0
      result = 0;
84
0
    break;
85
0
  case SORT_SIZE:
86
0
    result = sort_number_cmp(pa->size, pb->size);
87
0
    break;
88
0
  case SORT_ACTIVITY:
89
0
  case SORT_INDEX:
90
0
  case SORT_MODIFIER:
91
0
  case SORT_ORDER:
92
0
  case SORT_Z:
93
0
  case SORT_END:
94
0
    break;
95
0
  }
96
97
0
  if (result == 0)
98
0
    result = strcmp(pa->name, pb->name);
99
100
0
  if (sort_crit->reversed)
101
0
    result = -result;
102
0
  return (result);
103
0
}
104
105
static int
106
sort_client_cmp(const void *a0, const void *b0)
107
0
{
108
0
  struct sort_criteria    *sort_crit = sort_criteria;
109
0
  const struct client *const  *a = a0;
110
0
  const struct client *const  *b = b0;
111
0
  const struct client   *ca = *a;
112
0
  const struct client   *cb = *b;
113
0
  int        result = 0;
114
115
0
  switch (sort_crit->order) {
116
0
  case SORT_NAME:
117
0
    result = strcmp(ca->name, cb->name);
118
0
    break;
119
0
  case SORT_SIZE:
120
0
    result = sort_number_cmp(ca->tty.sx, cb->tty.sx);
121
0
    if (result == 0)
122
0
      result = sort_number_cmp(ca->tty.sy, cb->tty.sy);
123
0
    break;
124
0
  case SORT_CREATION:
125
0
    if (timercmp(&ca->creation_time, &cb->creation_time, >))
126
0
      result = 1;
127
0
    else if (timercmp(&ca->creation_time, &cb->creation_time, <))
128
0
      result = -1;
129
0
    break;
130
0
  case SORT_ACTIVITY:
131
0
    if (timercmp(&ca->activity_time, &cb->activity_time, >))
132
0
      result = -1;
133
0
    else if (timercmp(&ca->activity_time, &cb->activity_time, <))
134
0
      result = 1;
135
0
    break;
136
0
  case SORT_INDEX:
137
0
  case SORT_MODIFIER:
138
0
  case SORT_ORDER:
139
0
  case SORT_Z:
140
0
  case SORT_END:
141
0
    break;
142
0
  }
143
144
0
  if (result == 0)
145
0
    result = strcmp(ca->name, cb->name);
146
147
0
  if (sort_crit->reversed)
148
0
    result = -result;
149
0
  return (result);
150
0
}
151
152
static int
153
sort_session_cmp(const void *a0, const void *b0)
154
0
{
155
0
  struct sort_criteria    *sort_crit = sort_criteria;
156
0
  const struct session *const *a = a0;
157
0
  const struct session *const *b = b0;
158
0
  const struct session    *sa = *a;
159
0
  const struct session    *sb = *b;
160
0
  int        result = 0;
161
162
0
  switch (sort_crit->order) {
163
0
  case SORT_INDEX:
164
0
    result = sort_number_cmp(sa->id, sb->id);
165
0
    break;
166
0
  case SORT_CREATION:
167
0
    if (timercmp(&sa->creation_time, &sb->creation_time, >)) {
168
0
      result = 1;
169
0
      break;
170
0
    }
171
0
    if (timercmp(&sa->creation_time, &sb->creation_time, <)) {
172
0
      result = -1;
173
0
      break;
174
0
    }
175
0
    break;
176
0
  case SORT_ACTIVITY:
177
0
    if (timercmp(&sa->activity_time, &sb->activity_time, >)) {
178
0
      result = -1;
179
0
      break;
180
0
    }
181
0
    if (timercmp(&sa->activity_time, &sb->activity_time, <)) {
182
0
      result = 1;
183
0
      break;
184
0
    }
185
0
    break;
186
0
  case SORT_NAME:
187
0
    result = strcmp(sa->name, sb->name);
188
0
    break;
189
0
  case SORT_MODIFIER:
190
0
  case SORT_ORDER:
191
0
  case SORT_SIZE:
192
0
  case SORT_Z:
193
0
  case SORT_END:
194
0
    break;
195
0
  }
196
197
0
  if (result == 0)
198
0
    result = strcmp(sa->name, sb->name);
199
200
0
  if (sort_crit->reversed)
201
0
    result = -result;
202
0
  return (result);
203
0
}
204
205
static int
206
sort_pane_cmp(const void *a0, const void *b0)
207
0
{
208
0
  struct sort_criteria  *sort_crit = sort_criteria;
209
0
  struct window_pane  *a = *(struct window_pane **)a0;
210
0
  struct window_pane  *b = *(struct window_pane **)b0;
211
0
  int      result = 0;
212
0
  u_int      ai, bi;
213
214
0
  switch (sort_crit->order) {
215
0
  case SORT_ACTIVITY:
216
0
    result = sort_number_cmp(a->active_point, b->active_point);
217
0
    break;
218
0
  case SORT_CREATION:
219
0
    result = sort_number_cmp(a->id, b->id);
220
0
    break;
221
0
  case SORT_SIZE:
222
0
    result = sort_number_cmp(a->sx * a->sy, b->sx * b->sy);
223
0
    break;
224
0
  case SORT_INDEX:
225
0
    window_pane_index(a, &ai);
226
0
    window_pane_index(b, &bi);
227
0
    result = sort_number_cmp(ai, bi);
228
0
    break;
229
0
  case SORT_NAME:
230
0
    result = strcmp(a->screen->title, b->screen->title);
231
0
    break;
232
0
  case SORT_Z:
233
0
    window_pane_zindex(a, &ai);
234
0
    window_pane_zindex(b, &bi);
235
0
    result = sort_number_cmp(ai, bi);
236
0
    break;
237
0
  case SORT_MODIFIER:
238
0
  case SORT_ORDER:
239
0
  case SORT_END:
240
0
    break;
241
0
  }
242
243
0
  if (result == 0)
244
0
    result = strcmp(a->screen->title, b->screen->title);
245
246
0
  if (sort_crit->reversed)
247
0
    result = -result;
248
0
  return (result);
249
0
}
250
251
static int
252
sort_winlink_cmp(const void *a0, const void *b0)
253
0
{
254
0
  struct sort_criteria    *sort_crit = sort_criteria;
255
0
  const struct winlink *const *a = a0;
256
0
  const struct winlink *const *b = b0;
257
0
  const struct winlink    *wla = *a;
258
0
  const struct winlink    *wlb = *b;
259
0
  struct window     *wa = wla->window;
260
0
  struct window     *wb = wlb->window;
261
0
  int        result = 0;
262
263
0
  switch (sort_crit->order) {
264
0
  case SORT_INDEX:
265
0
    result = wla->idx - wlb->idx;
266
0
    break;
267
0
  case SORT_CREATION:
268
0
    if (timercmp(&wa->creation_time, &wb->creation_time, >)) {
269
0
      result = 1;
270
0
      break;
271
0
    }
272
0
    if (timercmp(&wa->creation_time, &wb->creation_time, <)) {
273
0
      result = -1;
274
0
      break;
275
0
    }
276
0
    break;
277
0
  case SORT_ACTIVITY:
278
0
    if (timercmp(&wa->activity_time, &wb->activity_time, >)) {
279
0
      result = -1;
280
0
      break;
281
0
    }
282
0
    if (timercmp(&wa->activity_time, &wb->activity_time, <)) {
283
0
      result = 1;
284
0
      break;
285
0
    }
286
0
    break;
287
0
  case SORT_NAME:
288
0
    result = strcmp(wa->name, wb->name);
289
0
    break;
290
0
  case SORT_SIZE:
291
0
    result = sort_number_cmp(wa->sx * wa->sy, wb->sx * wb->sy);
292
0
    break;
293
0
  case SORT_MODIFIER:
294
0
  case SORT_ORDER:
295
0
  case SORT_Z:
296
0
  case SORT_END:
297
0
    break;
298
0
  }
299
300
0
  if (result == 0)
301
0
    result = strcmp(wa->name, wb->name);
302
303
0
  if (sort_crit->reversed)
304
0
    result = -result;
305
0
  return (result);
306
0
}
307
308
static int
309
sort_key_binding_cmp(const void *a0, const void *b0)
310
0
{
311
0
  struct sort_criteria    *sort_crit = sort_criteria;
312
0
  const struct key_binding  *a = *(struct key_binding **)a0;
313
0
  const struct key_binding  *b = *(struct key_binding **)b0;
314
0
  int        result = 0;
315
0
  key_code       ak, bk;
316
317
0
  switch (sort_crit->order) {
318
0
  case SORT_INDEX:
319
0
    result = sort_number_cmp(a->key, b->key);
320
0
    break;
321
0
  case SORT_MODIFIER:
322
0
    ak = (a->key & KEYC_MASK_MODIFIERS);
323
0
    bk = (b->key & KEYC_MASK_MODIFIERS);
324
0
    result = sort_number_cmp(ak, bk);
325
0
    break;
326
0
  case SORT_NAME:
327
0
    result = strcasecmp(a->tablename, b->tablename);
328
0
    break;
329
0
  case SORT_ACTIVITY:
330
0
  case SORT_CREATION:
331
0
  case SORT_ORDER:
332
0
  case SORT_SIZE:
333
0
  case SORT_Z:
334
0
  case SORT_END:
335
0
    break;
336
0
  }
337
338
0
  if (result == 0)
339
0
    result = strcasecmp(a->tablename, b->tablename);
340
0
  if (result == 0)
341
0
    result = sort_number_cmp(a->key, b->key);
342
343
0
  if (sort_crit->reversed)
344
0
    result = -result;
345
0
  return (result);
346
0
}
347
348
void
349
sort_next_order(struct sort_criteria *sort_crit)
350
0
{
351
0
  u_int i;
352
353
0
  if (sort_crit->order_seq == NULL)
354
0
    return;
355
0
  for (i = 0; sort_crit->order_seq[i] != SORT_END; i++) {
356
0
    if (sort_crit->order == sort_crit->order_seq[i])
357
0
      break;
358
0
  }
359
360
0
  if (sort_crit->order_seq[i] == SORT_END)
361
0
    i = 0;
362
0
  else {
363
0
    i++;
364
0
    if (sort_crit->order_seq[i] == SORT_END)
365
0
      i = 0;
366
0
  }
367
0
  sort_crit->order = sort_crit->order_seq[i];
368
0
}
369
370
enum sort_order
371
sort_order_from_string(const char* order)
372
0
{
373
0
  if (order != NULL) {
374
0
    if (strcasecmp(order, "activity") == 0)
375
0
      return (SORT_ACTIVITY);
376
0
    if (strcasecmp(order, "creation") == 0)
377
0
      return (SORT_CREATION);
378
0
    if (strcasecmp(order, "index") == 0 ||
379
0
        strcasecmp(order, "key") == 0)
380
0
      return (SORT_INDEX);
381
0
    if (strcasecmp(order, "modifier") == 0)
382
0
      return (SORT_MODIFIER);
383
0
    if (strcasecmp(order, "name") == 0 ||
384
0
        strcasecmp(order, "title") == 0)
385
0
      return (SORT_NAME);
386
0
    if (strcasecmp(order, "order") == 0)
387
0
      return (SORT_ORDER);
388
0
    if (strcasecmp(order, "size") == 0)
389
0
      return (SORT_SIZE);
390
0
    if (strcasecmp(order, "z") == 0)
391
0
      return (SORT_Z);
392
0
  }
393
0
  return (SORT_END);
394
0
}
395
396
const char *
397
sort_order_to_string(enum sort_order order)
398
0
{
399
0
  if (order == SORT_ACTIVITY)
400
0
    return "activity";
401
0
  if (order == SORT_CREATION)
402
0
    return "creation";
403
0
  if (order == SORT_INDEX)
404
0
    return "index";
405
0
  if (order == SORT_MODIFIER)
406
0
    return "modifier";
407
0
  if (order == SORT_NAME)
408
0
    return "name";
409
0
  if (order == SORT_ORDER)
410
0
    return "order";
411
0
  if (order == SORT_SIZE)
412
0
    return "size";
413
0
  if (order == SORT_Z)
414
0
    return "z";
415
0
  return (NULL);
416
0
}
417
418
int
419
sort_would_window_tree_swap(struct sort_criteria *sort_crit,
420
    struct winlink *wla, struct winlink *wlb)
421
0
{
422
0
  if (sort_crit->order == SORT_INDEX)
423
0
    return (0);
424
0
  sort_criteria = sort_crit;
425
0
  return (sort_winlink_cmp(&wla, &wlb) != 0);
426
0
}
427
428
struct paste_buffer **
429
sort_get_buffers(u_int *n, struct sort_criteria *sort_crit)
430
0
{
431
0
  struct paste_buffer    *pb = NULL;
432
0
  u_int         i;
433
0
  static struct paste_buffer  **l = NULL;
434
0
  static u_int        lsz = 0;
435
436
0
  i = 0;
437
0
  while ((pb = paste_walk(pb)) != NULL) {
438
0
    if (lsz <= i) {
439
0
      lsz += 100;
440
0
      l = xreallocarray(l, lsz, sizeof *l);
441
0
    }
442
0
    l[i++] = pb;
443
0
  }
444
445
0
  sort_qsort(l, i, sizeof *l, sort_buffer_cmp, sort_crit);
446
0
  *n = i;
447
448
0
  return (l);
449
0
}
450
451
struct client **
452
sort_get_clients(u_int *n, struct sort_criteria *sort_crit)
453
1.67k
{
454
1.67k
  struct client    *c;
455
1.67k
  u_int       i;
456
1.67k
  static struct client  **l = NULL;
457
1.67k
  static u_int      lsz = 0;
458
459
1.67k
  i = 0;
460
1.67k
  TAILQ_FOREACH(c, &clients, entry) {
461
0
    if (c->flags & CLIENT_UNATTACHEDFLAGS)
462
0
      continue;
463
0
    if (~c->flags & CLIENT_ATTACHED)
464
0
      continue;
465
0
    if (lsz <= i) {
466
0
      lsz += 100;
467
0
      l = xreallocarray(l, lsz, sizeof *l);
468
0
    }
469
0
    l[i++] = c;
470
0
  }
471
472
1.67k
  sort_qsort(l, i, sizeof *l, sort_client_cmp, sort_crit);
473
1.67k
  *n = i;
474
475
1.67k
  return (l);
476
1.67k
}
477
478
struct session **
479
sort_get_sessions(u_int *n, struct sort_criteria *sort_crit)
480
17.5k
{
481
17.5k
  struct session     *s;
482
17.5k
  u_int       i;
483
17.5k
  static struct session **l = NULL;
484
17.5k
  static u_int      lsz = 0;
485
486
17.5k
  i = 0;
487
17.5k
  RB_FOREACH(s, sessions, &sessions) {
488
0
    if (lsz <= i) {
489
0
      lsz += 100;
490
0
      l = xreallocarray(l, lsz, sizeof *l);
491
0
    }
492
0
    l[i++] = s;
493
0
  }
494
495
17.5k
  sort_qsort(l, i, sizeof *l, sort_session_cmp, sort_crit);
496
17.5k
  *n = i;
497
498
17.5k
  return (l);
499
17.5k
}
500
501
struct window_pane **
502
sort_get_panes(u_int *n, struct sort_criteria *sort_crit)
503
0
{
504
0
  struct session       *s;
505
0
  struct winlink       *wl;
506
0
  struct window      *w;
507
0
  struct window_pane     *wp;
508
0
  u_int         i;
509
0
  static struct window_pane **l = NULL;
510
0
  static u_int        lsz = 0;
511
512
0
  i = 0;
513
0
  RB_FOREACH(s, sessions, &sessions) {
514
0
    RB_FOREACH(wl, winlinks, &s->windows)  {
515
0
      w = wl->window;
516
0
      TAILQ_FOREACH(wp, &w->panes, entry) {
517
0
        if (lsz <= i) {
518
0
          lsz += 100;
519
0
          l = xreallocarray(l, lsz, sizeof *l);
520
0
        }
521
0
        l[i++] = wp;
522
0
      }
523
0
    }
524
0
  }
525
526
0
  sort_qsort(l, i, sizeof *l, sort_pane_cmp, sort_crit);
527
0
  *n = i;
528
529
0
  return (l);
530
0
}
531
532
struct window_pane **
533
sort_get_panes_session(struct session *s, u_int *n,
534
    struct sort_criteria *sort_crit)
535
0
{
536
0
  struct winlink       *wl = NULL;
537
0
  struct window      *w = NULL;
538
0
  struct window_pane     *wp = NULL;
539
0
  u_int         i;
540
0
  static struct window_pane **l = NULL;
541
0
  static u_int        lsz = 0;
542
543
0
  i = 0;
544
0
  RB_FOREACH(wl, winlinks, &s->windows)  {
545
0
    w = wl->window;
546
0
    TAILQ_FOREACH(wp, &w->panes, entry) {
547
0
      if (lsz <= i) {
548
0
        lsz += 100;
549
0
        l = xreallocarray(l, lsz, sizeof *l);
550
0
      }
551
0
      l[i++] = wp;
552
0
    }
553
0
  }
554
555
0
  sort_qsort(l, i, sizeof *l, sort_pane_cmp, sort_crit);
556
0
  *n = i;
557
558
0
  return (l);
559
0
}
560
561
struct window_pane **
562
sort_get_panes_window(struct window *w, u_int *n,
563
    struct sort_criteria *sort_crit)
564
0
{
565
0
  struct window_pane     *wp;
566
0
  u_int         i;
567
0
  static struct window_pane **l = NULL;
568
0
  static u_int        lsz = 0;
569
570
0
  i = 0;
571
0
  TAILQ_FOREACH(wp, &w->panes, entry) {
572
0
    if (lsz <= i) {
573
0
      lsz += 100;
574
0
      l = xreallocarray(l, lsz, sizeof *l);
575
0
    }
576
0
    l[i++] = wp;
577
0
  }
578
579
0
  sort_qsort(l, i, sizeof *l, sort_pane_cmp, sort_crit);
580
0
  *n = i;
581
582
0
  return (l);
583
0
}
584
585
struct winlink **
586
sort_get_winlinks(u_int *n, struct sort_criteria *sort_crit)
587
0
{
588
0
  struct session     *s;
589
0
  struct winlink     *wl;
590
0
  u_int       i;
591
0
  static struct winlink **l = NULL;
592
0
  static u_int      lsz = 0;
593
594
0
  i = 0;
595
0
  RB_FOREACH(s, sessions, &sessions) {
596
0
    RB_FOREACH(wl, winlinks, &s->windows) {
597
0
      if (lsz <= i) {
598
0
        lsz += 100;
599
0
        l = xreallocarray(l, lsz, sizeof *l);
600
0
      }
601
0
      l[i++] = wl;
602
0
    }
603
0
  }
604
605
0
  sort_qsort(l, i, sizeof *l, sort_winlink_cmp, sort_crit);
606
0
  *n = i;
607
608
0
  return (l);
609
0
}
610
611
struct winlink **
612
sort_get_winlinks_session(struct session *s, u_int *n,
613
    struct sort_criteria *sort_crit)
614
0
{
615
0
  struct winlink     *wl;
616
0
  u_int       i;
617
0
  static struct winlink **l = NULL;
618
0
  static u_int      lsz = 0;
619
620
0
  i = 0;
621
0
  RB_FOREACH(wl, winlinks, &s->windows) {
622
0
    if (lsz <= i) {
623
0
      lsz += 100;
624
0
      l = xreallocarray(l, lsz, sizeof *l);
625
0
    }
626
0
    l[i++] = wl;
627
0
  }
628
629
0
  sort_qsort(l, i, sizeof *l, sort_winlink_cmp, sort_crit);
630
0
  *n = i;
631
632
0
  return (l);
633
0
}
634
635
struct key_binding **
636
sort_get_key_bindings(u_int *n, struct sort_criteria *sort_crit)
637
0
{
638
0
  struct key_table     *table;
639
0
  struct key_binding     *bd;
640
0
  u_int         i = 0;
641
0
  static struct key_binding **l = NULL;
642
0
  static u_int        lsz = 0;
643
644
0
  table = key_bindings_first_table();
645
0
  while (table != NULL) {
646
0
    bd = key_bindings_first(table);
647
0
    while (bd != NULL) {
648
0
      if (lsz <= i) {
649
0
        lsz += 100;
650
0
        l = xreallocarray(l, lsz, sizeof *l);
651
0
      }
652
0
      l[i++] = bd;
653
0
      bd = key_bindings_next(table, bd);
654
0
    }
655
0
    table = key_bindings_next_table(table);
656
0
  }
657
658
0
  sort_qsort(l, i, sizeof *l, sort_key_binding_cmp, sort_crit);
659
0
  *n = i;
660
661
0
  return (l);
662
0
}
663
664
struct key_binding **
665
sort_get_key_bindings_table(struct key_table *table, u_int *n,
666
    struct sort_criteria *sort_crit)
667
0
{
668
0
  struct key_binding     *bd;
669
0
  u_int         i = 0;
670
0
  static struct key_binding **l = NULL;
671
0
  static u_int        lsz = 0;
672
673
0
  bd = key_bindings_first(table);
674
0
  while (bd != NULL) {
675
0
    if (lsz <= i) {
676
0
      lsz += 100;
677
0
      l = xreallocarray(l, lsz, sizeof *l);
678
0
    }
679
0
    l[i++] = bd;
680
0
    bd = key_bindings_next(table, bd);
681
0
  }
682
683
0
  sort_qsort(l, i, sizeof *l, sort_key_binding_cmp, sort_crit);
684
0
  *n = i;
685
686
0
  return (l);
687
0
}