kulp / tenyr
1
#define _XOPEN_SOURCE (700) /* for strdup */
2

3
#include "os_common.h"
4

5
#include "param.h"
6

7
#include <search.h>
8
#include <stdlib.h>
9
#include <string.h>
10

11
struct param_state {
12
#define DEFAULT_PARAMS_COUNT 16
13
    lfind_size_t params_count;
14
    size_t params_size;
15
    struct param_entry {
16
        char *key;
17
        unsigned free_key; ///< whether key should be free()d
18
        struct string_list {
19
            struct string_list *next;
20
            void *value;
21
            unsigned free_value; ///< whether value should be free()d
22
        } *list;
23
    } *params;
24
};
25

26
static void param_free(struct param_entry *p);
27

28 1
static int params_cmp(const void *_a, const void *_b)
29
{
30 1
    const struct param_entry *a = _a,
31 1
                             *b = _b;
32

33 1
    return strcmp(a->key, b->key);
34
}
35

36 1
int param_get_int(struct param_state *pstate, const char *key, int *val)
37
{
38 1
    const char *str = NULL;
39 1
    char *next = NULL;
40 1
    long test = 0;
41 1
    if (param_get(pstate, key, 1, (const void **)&str) && str != NULL)
42 1
        test = strtol(str, &next, 0);
43

44 1
    int good = next > str;
45 1
    if (good)
46 1
        *val = (int)test;
47

48 1
    return good;
49
}
50

51
// Returns the number of parameters with the given key, filling the first
52
// `count` of them into the supplied `val` array
53 1
int param_get(struct param_state *pstate, const char *key, size_t count, const void **val)
54
{
55 1
    if (!pstate) return 0; // permit calling with NULL param set
56

57 1
    const struct param_entry p = { .key = (char*)key };
58

59 1
    struct param_entry *q = lfind(&p, pstate->params, &pstate->params_count,
60
                                        sizeof *pstate->params, params_cmp);
61

62 1
    if (!q)
63 1
        return 0;
64

65 1
    int i = 0;
66 1
    for (struct string_list *r = q->list; r; r = r->next, i++)
67 1
        if (i < (ssize_t)count)
68 1
            val[i] = r->value;
69

70 1
    return i;
71
}
72

73 1
int param_set(struct param_state *pstate, char *key, void *val, int replace, int free_key, int free_value)
74
{
75 1
    if (!pstate) return 0; // permit calling with NULL param set
76

77 1
    if (pstate->params_size <= pstate->params_count) {
78 1
        while (pstate->params_size <= pstate->params_count)
79 1
            pstate->params_size *= 2;
80
        // technically there is a problem here if realloc() fails
81 1
        pstate->params = realloc(pstate->params, pstate->params_size * sizeof *pstate->params);
82
    }
83

84 1
    struct param_entry p = { .key  = key, .free_key = !!free_key }; // doesn't have a list yet
85 1
    struct param_entry *q = lsearch(&p, pstate->params, &pstate->params_count,
86
                                        sizeof *pstate->params, params_cmp);
87

88 1
    if (!q)
89 0
        return 1; // errno will be set
90

91 1
    struct string_list *list = calloc(1, sizeof *list);
92 1
    list->next = NULL;
93 1
    list->value = val;
94 1
    list->free_value = !!free_value;
95

96 1
    if (replace) {
97 1
        if (q->key != p.key) {
98 1
            param_free(q);
99 1
            *q = p;
100
        }
101 1
        q->list = list;
102
    } else {
103 1
        if (!q->list) {
104 1
            q->list = list;
105
        } else {
106 1
            struct string_list *r = q->list;
107 1
            while (r->next)
108 1
                r = r->next;
109 1
            r->next = list;
110
        }
111
    }
112

113 1
    return 0;
114
}
115

116 1
int param_add(struct param_state *pstate, const char *optarg)
117
{
118 1
    if (!pstate) return 0; // permit calling with NULL param set
119

120
    // We can't use getsubopt() here because we don't know what all of our
121
    // options are ahead of time.
122 1
    char *dupped = strdup(optarg);
123 1
    char *eq = strchr(dupped, '=');
124 1
    if (!eq) {
125 0
        free(dupped);
126 0
        return 1;
127
    }
128

129
    // Replace '=' with '\0' to split string in two
130 1
    *eq = '\0';
131

132 1
    int replace = eq[-1] != '+';
133 1
    if (!replace)
134 1
        eq[-1] = '\0';
135

136 1
    return param_set(pstate, dupped, ++eq, replace, 1, 0);
137
}
138

139 1
void param_init(struct param_state **pstate)
140
{
141 1
    struct param_state *p = *pstate = calloc(1, sizeof **pstate);
142 1
    p->params_size  = DEFAULT_PARAMS_COUNT;
143 1
    p->params_count = 0;
144 1
    p->params       = calloc(p->params_size, sizeof *p->params);
145
}
146

147 1
void param_destroy(struct param_state *pstate)
148
{
149 1
    while (pstate->params_count > 0)
150 1
        param_free(&pstate->params[--pstate->params_count]);
151

152 1
    free(pstate->params);
153 1
    free(pstate);
154
}
155

156 1
static void param_free(struct param_entry *p)
157
{
158 1
    if (p->free_key)
159 1
        free(p->key);
160 1
    struct string_list *q = p->list;
161 1
    while (q) {
162 1
        if (q->free_value)
163 1
            free(q->value);
164 1
        struct string_list *r = q;
165 1
        q = q->next;
166 1
        free(r);
167
    }
168
}
169

170
/* vi: set ts=4 sw=4 et: */

Read our documentation on viewing source code .

Loading