summaryrefslogtreecommitdiff
path: root/clients/vlist.c
blob: 933b704fbbb74ccd9ef1cdac297fb46926e07b65 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
#include <stdlib.h>
#include <string.h>

#include "vlist.h"

static const char *const SORT_NAMES[VSORT_COUNT] = {
    "number", "number-desc", "date", "date-desc",
};

static const char *const SORT_LABELS[VSORT_COUNT] = {
    "nummer, stigande", "nummer, fallande", "datum, stigande",
    "datum, fallande",
};

static int cmp_i64(int64_t a, int64_t b)
{
    return a < b ? -1 : a > b;
}

static int cmp_number(const struct vlist_item *a, const struct vlist_item *b)
{
    int c = strcmp(a->series, b->series);
    if (c)
        return c;
    return cmp_i64(a->number, b->number);
}

static int g_mode; /* qsort has no context argument in C11 */

static int cmp_items(const void *pa, const void *pb)
{
    const struct vlist_item *a = pa, *b = pb;
    int desc = g_mode == VSORT_NUMBER_DESC || g_mode == VSORT_DATE_DESC;
    int c = 0;
    if (g_mode == VSORT_DATE || g_mode == VSORT_DATE_DESC)
        c = strcmp(a->date, b->date);
    if (!c)
        c = cmp_number(a, b);
    if (!c)
        c = cmp_i64(a->id, b->id);
    return desc ? -c : c;
}

void vlist_sort(struct vlist_item *v, size_t n, int mode)
{
    if (!v || n < 2)
        return;
    g_mode = mode >= 0 && mode < VSORT_COUNT ? mode : VSORT_NUMBER;
    qsort(v, n, sizeof *v, cmp_items);
}

const char *vlist_sort_label(int mode)
{
    return SORT_LABELS[mode >= 0 && mode < VSORT_COUNT ? mode : 0];
}

const char *vlist_sort_name(int mode)
{
    return SORT_NAMES[mode >= 0 && mode < VSORT_COUNT ? mode : 0];
}

int vlist_sort_parse(const char *name)
{
    for (int i = 0; name && i < VSORT_COUNT; i++)
        if (strcmp(name, SORT_NAMES[i]) == 0)
            return i;
    return VSORT_NUMBER;
}

int vlist_index(const struct vlist_item *v, size_t n, int64_t id)
{
    for (size_t i = 0; i < n; i++)
        if (v[i].id == id)
            return (int)i;
    return -1;
}

int vlist_step(size_t n, int idx, int dir)
{
    if (idx < 0 || (size_t)idx >= n)
        return -1;
    int next = idx + (dir < 0 ? -1 : 1);
    return next >= 0 && (size_t)next < n ? next : -1;
}