source: libabac/abac_keyid_map.c @ ebf0ae2

tvf-new-xml
Last change on this file since ebf0ae2 was ebf0ae2, checked in by Ted Faber <faber@…>, 11 years ago

Return a strdup as it is intended to be freed by the caller.

  • Property mode set to 100644
File size: 5.4 KB
Line 
1/* abac_keyid_map.c */
2
3
4#include "abac.h"
5#include "abac_util.h"
6#include "uthash.h"
7
8struct abac_keyid_mapping_t {
9    char *key;
10    char *value;
11    UT_hash_handle hh;
12};
13
14struct abac_keyid_map_t {
15    abac_keyid_mapping_t *keys;
16    abac_keyid_mapping_t *nicknames;
17    int refcount;
18};
19
20abac_keyid_mapping_t *abac_keyid_mapping_new(char *k, char *v) {
21    abac_keyid_mapping_t *m = NULL;
22
23    if ( !k || ! v) return NULL;
24    m = abac_xmalloc(sizeof(abac_keyid_mapping_t));
25    m->key = abac_xstrdup(k);
26    m->value = abac_xstrdup(v);
27
28    return m;
29}
30
31void abac_keyid_mapping_free(abac_keyid_mapping_t *m) {
32    if ( m->key ) free(m->key);
33    if ( m->value ) free(m->value);
34    free(m);
35}
36
37abac_keyid_map_t *abac_keyid_map_new() {
38    abac_keyid_map_t *m = abac_xmalloc(sizeof(abac_keyid_map_t));
39
40    m->keys = NULL;
41    m->nicknames = NULL;
42    m->refcount = 1;
43    return m;
44}
45
46/* Make a new, independent copy of the old keymap. */
47abac_keyid_map_t *abac_keyid_map_clone(abac_keyid_map_t *old) {
48    abac_keyid_map_t *m = abac_xmalloc(sizeof(abac_keyid_map_t));
49    abac_keyid_mapping_t *me = NULL;
50
51    m->keys = NULL;
52    m->nicknames = NULL;
53    m->refcount = 1;
54
55    for ( me = old->keys; me ; me = me->hh.next) 
56        abac_keyid_map_add_nickname(m, me->key, me->value);
57
58    return m;
59}
60
61/* Add a reference to old and return it. */
62abac_keyid_map_t *abac_keyid_map_dup(abac_keyid_map_t *old) {
63    old->refcount ++;
64    return old;
65}
66
67void abac_keyid_map_free(abac_keyid_map_t *m) {
68    abac_keyid_mapping_t *me = NULL;
69
70    if ( --m->refcount > 0) return;
71
72    while ( (me = m->keys) ) {
73        HASH_DEL(m->keys, me);
74        abac_keyid_mapping_free(me);
75    }
76    while ( (me = m->nicknames) ) {
77        HASH_DEL(m->nicknames, me);
78        abac_keyid_mapping_free(me);
79    }
80    free(m);
81}
82
83char *abac_keyid_map_key_to_nickname(abac_keyid_map_t *m, char *key) {
84    abac_keyid_mapping_t *me = NULL;
85
86    if ( !key || !m) return 0;
87    HASH_FIND_STR(m->keys, key, me);
88
89    if ( me ) return abac_xstrdup(me->value);
90    else return NULL;
91}
92
93char *abac_keyid_map_nickname_to_key(abac_keyid_map_t *m, char *nick) {
94    abac_keyid_mapping_t *me = NULL;
95
96    if ( !nick || !m ) return 0;
97    HASH_FIND_STR(m->nicknames, nick, me);
98
99    if ( me ) return abac_xstrdup(me->value);
100    else return NULL;
101}
102
103int abac_keyid_map_remove_keyid(abac_keyid_map_t *m, char *key) {
104    abac_keyid_mapping_t *me = NULL;
105    abac_keyid_mapping_t *nne = NULL;
106
107    HASH_FIND_STR(m->keys, key, me);
108    if ( !me ) return 0;
109    HASH_FIND_STR(m->nicknames, me->value, nne);
110    /* delete from keys */
111    HASH_DEL(m->keys, me);
112    abac_keyid_mapping_free(me);
113    /* If we found a nickname, delete that too */
114    if ( nne ) { 
115        HASH_DEL(m->nicknames, nne);
116        abac_keyid_mapping_free(nne);
117    }
118    return 1;
119}
120
121
122int abac_keyid_map_add_nickname(abac_keyid_map_t *m, char *key, char *nick) {
123    abac_keyid_mapping_t *me = NULL;
124    char *name = NULL;
125    int i =0;
126
127    if ( !key || !nick) return 0;
128    if (abac_keyid_map_key_to_nickname(m, key)) return 0;
129
130    if ( !(name = abac_xmalloc(strlen(nick)+10))) return 0;
131    sprintf(name, "%s", nick);
132
133    while (abac_keyid_map_nickname_to_key(m, name) && i < 1000) 
134        sprintf(name, "%s%05d", nick, i++);
135
136    if ( i < 1000 ) {
137        me = abac_keyid_mapping_new(key, name);
138        HASH_ADD_KEYPTR(hh, m->keys, me->key, strlen(me->key), me);
139        me = abac_keyid_mapping_new(name, key);
140        HASH_ADD_KEYPTR(hh, m->nicknames, me->key, strlen(me->key), me);
141    }
142    free(name);
143    return 1;
144}
145
146void abac_keyid_map_merge(abac_keyid_map_t *dest, abac_keyid_map_t *src, 
147        int overwrite) {
148    abac_keyid_mapping_t *me = NULL;
149    if ( !dest || !src ) return;
150
151    for (me = src->keys; me; me = me->hh.next) {
152        char *n = abac_keyid_map_key_to_nickname(dest, me->key);
153        if ( n ) {
154            free(n);
155            if ( overwrite) {
156                abac_keyid_map_remove_keyid(dest,me->key);
157                abac_keyid_map_add_nickname(dest, me->key, me->value);
158            }
159        } else {
160            abac_keyid_map_add_nickname(dest, me->key, me->value);
161        }
162    }
163}
164
165static int is_sep(char *c) {
166    switch (*c) {
167        case ' ':
168        case '_':
169        case '.':
170            return 1;
171        default:
172            return 0;
173    }
174}
175
176static char *abac_keyid_map_replace(abac_keyid_map_t *m, char *s, 
177        char *(*lookup)(abac_keyid_map_t *, char *)) {
178    int lim = strlen(s);
179    int i; 
180    int sz = 0;
181    char *rv = NULL;
182    char *start = s;
183    char old = '\0';
184    char *repl = NULL;
185    char *newrv = NULL;
186    int newlen = 0;
187
188    for ( i = 0; i < lim; i++ ) {
189        if ( is_sep(s+i) ) {
190            old = s[i];
191            s[i] = '\0';
192           
193            if ( !(repl = lookup(m, start)) ) repl = start;
194
195            newlen = strlen(repl)+1;
196
197            if ( !(newrv = realloc(rv, sz + newlen +1)) ) {
198                if ( rv ) free(rv);
199                return NULL;
200            } else {
201                rv = newrv;
202                if (sz == 0 ) 
203                    rv[0] = '\0';
204                sz += newlen;
205            }
206            strncat(rv, repl, newlen);
207            rv[sz-1] = old;
208            rv[sz] = '\0';
209            s[i] = old;
210            start = s+i+1;
211        }
212    }
213    if ( start != s+i ) {
214        if ( !(repl = lookup(m, start)) ) repl = start;
215
216        newlen = strlen(repl);
217
218        if ( !(newrv = realloc(rv, sz + newlen)) ) {
219            if ( rv ) free(rv);
220            return NULL;
221        } else {
222            rv = newrv;
223            if ( sz == 0) 
224                rv[0] = '\0';
225            sz += newlen;
226        }
227        strncat(rv, repl, newlen);
228    }
229    return rv;
230}
231
232char *abac_keyid_map_expand_key(abac_keyid_map_t *m, char *s) {
233    return abac_keyid_map_replace(m , s, abac_keyid_map_key_to_nickname);
234}
235
236char *abac_keyid_map_expand_nickname(abac_keyid_map_t *m, char *s) {
237    return abac_keyid_map_replace(m , s, abac_keyid_map_nickname_to_key);
238}
Note: See TracBrowser for help on using the repository browser.