00001 #include "../stdafx.h"
00002 #include <stdlib.h>
00003 #include <stdio.h>
00004 #include <string.h>
00005 #include <assert.h>
00006 #include <regex.h>
00007 #if defined(_WINDOWS) && !defined(_CYGWIN)
00008 #include "wincompat.h"
00009 #endif
00010 #include "utils.h"
00011 #include "plist.h"
00012 #include "ptree.h"
00013 #include "pdict-impl.h"
00014
00015 typedef struct pdict_ent pdict_ent_t;
00016 typedef int (*pdict_walk_int_func_t)(pdict_ent_t *pde, void *arg);
00017
00018 static int _pdict_ent_add_persistent_change_listeners(pdict_t *pd,
00019 pdict_ent_t *pde);
00020 static int _pdict_ent_add_persistent_change_listener(pdict_ent_t *pde,
00021 pdict_persistent_listener_t *pl);
00022 static int _pdict_ent_remove_persistent_change_listener(pdict_ent_t *pde,
00023 pdict_persistent_listener_t *pl);
00024 static void _pdict_ent_notify(pdict_ent_t *pde, int reason, const char *ov);
00025 static int _pdict_ent_add_change_listener(pdict_ent_t *pde,
00026 pdl_notify_func_t notify, void *arg);
00027 static int _pdict_walk_int(pdict_t *pd, pdict_walk_int_func_t w, void *arg);
00028 static int _pdict_ent_remove_change_listener(pdict_ent_t *pde,
00029 pdl_notify_func_t notify, void *a);
00030
00031 pdict_t *
00032 pdict_alloc(void)
00033 {
00034 pdict_t *pd;
00035
00036 if (!(pd = malloc(sizeof (*pd))))
00037 return 0;
00038 memset(pd, 0, sizeof (*pd));
00039
00040 return pd;
00041 }
00042
00043 static int
00044 pdecmp(const void *sv, const void *dv)
00045 {
00046 return strcmp(*(char **)sv, *(char **)dv);
00047 }
00048
00049 static int
00050 pdict_ent_remove_change_listeners_cb(const void *v, const void *v0, void *a)
00051 {
00052 free((void *)v); v = NULL;
00053 return (1);
00054 }
00055
00056 static int
00057 pdict_ent_remove_change_listeners(pdict_ent_t *pde)
00058 {
00059 plist_walk(pde->pde_listeners, pdict_ent_remove_change_listeners_cb, 0);
00060 plist_clear(&pde->pde_listeners);
00061 return 1;
00062 }
00063
00064 static int
00065 pdict_ent_listeners_copy_cb(const void *v, const void *v0, void *a)
00066 {
00067 pdict_listener_t *pdl = (pdict_listener_t *)v;
00068 pdict_ent_t *pde_ent_copy = a;
00069
00070 return _pdict_ent_add_change_listener(pde_ent_copy, pdl->pdl_notify, pdl->pdl_arg);
00071 }
00072
00073 static void
00074 _pdict_ent_listeners_copy(pdict_ent_t *pde, pdict_ent_t *pde_copy)
00075 {
00076 plist_walk(pde->pde_listeners, pdict_ent_listeners_copy_cb, pde_copy);
00077 }
00078
00079
00080
00081
00082 int
00083 pdict_add(pdict_t *pd, const char *k, const char *v, const char **ovp)
00084 {
00085 pdict_ent_t *n;
00086 pdict_ent_t n_copy;
00087 const char *ov;
00088
00089 if (!(k = strdup(k)))
00090 return 0;
00091 if (!(v = strdup(v))) {
00092 free((void *)k); k = NULL;
00093 return 0;
00094 }
00095 memset(&n_copy, 0, sizeof(pdict_ent_t));
00096 if (ptree_contains((void *)&k, pd->pd_ents, pdecmp, (void *)&n)) {
00097 free((void *)k); k = NULL;
00098 ov = n->pde_val;
00099 n->pde_val = v;
00100
00101 if (ovp)
00102 *ovp = ov;
00103 else {
00104 free((void *)ov); ov = NULL;
00105 }
00106
00107
00108 if(n->pde_listeners)
00109 {
00110 n_copy.pde_key = strdup(n->pde_key);
00111 n_copy.pde_val = strdup(n->pde_val);
00112 _pdict_ent_listeners_copy(n, &n_copy);
00113 _pdict_ent_notify(&n_copy, PDR_VALUE_CHANGED, ov);
00114 pdict_ent_remove_change_listeners(&n_copy);
00115 free((char *)n_copy.pde_key);
00116 free((char *)n_copy.pde_val);
00117 }
00118 return 1;
00119 }
00120 if (!(n = malloc(sizeof (*n)))) {
00121 free((void *)k); k = NULL;
00122 free((void *)v); v = NULL;
00123 return (0);
00124 }
00125 memset(n, 0, sizeof (*n));
00126 n->pde_key = k;
00127 n->pde_val = v;
00128
00129
00130 if (!_pdict_ent_add_persistent_change_listeners(pd, n)) {
00131 free((void *)k); k = NULL;
00132 free((void *)v); v = NULL;
00133 free(n); n = NULL;
00134 return (0);
00135 }
00136
00137 if (!ptree_replace(n, &pd->pd_ents, pdecmp, NULL)) {
00138 pdict_ent_remove_change_listeners(n);
00139 free((void *)k); k = NULL;
00140 free((void *)v); v = NULL;
00141 free(n); n = NULL;
00142 return (0);
00143 }
00144
00145 if(n->pde_listeners)
00146 {
00147 n_copy.pde_key = strdup(n->pde_key);
00148 n_copy.pde_val = strdup(n->pde_val);
00149 _pdict_ent_listeners_copy(n, &n_copy);
00150 _pdict_ent_notify(&n_copy, PDR_ENTRY_ADDED, n_copy.pde_val);
00151 pdict_ent_remove_change_listeners(&n_copy);
00152 free((char *)n_copy.pde_key);
00153 free((char *)n_copy.pde_val);
00154 }
00155
00156 if (ovp)
00157 *ovp = NULL;
00158
00159 return 1;
00160 }
00161
00162 int
00163 pdict_ent_remove(pdict_t *pd, const char *k, char **ovp)
00164 {
00165 pdict_ent_t *n;
00166
00167 pu_log(PUL_VERB, 0, "Removing in key pdict_ent_remove: %s", k);
00168
00169 if (!ptree_remove((void *)&k, &pd->pd_ents, pdecmp, (void *)&n))
00170 {
00171
00172 return 0;
00173 }
00174
00175 _pdict_ent_notify(n, PDR_ENTRY_REMOVING, n->pde_val);
00176
00177 if (ovp)
00178 *ovp = (char *)n->pde_val;
00179 else {
00180 free((void *)n->pde_val);
00181 }
00182 free((void *)n->pde_key);
00183 pdict_ent_remove_change_listeners(n);
00184 free(n);
00185 return 1;
00186 }
00187
00188 static int
00189 pdict_ent_remove_persistent_change_listener_cb(const void *pl, const void *v,
00190 void *a)
00191 {
00192 _pdict_ent_remove_persistent_change_listener((pdict_ent_t *)a,
00193 (pdict_persistent_listener_t *)pl);
00194 return 1;
00195 }
00196
00197 static int
00198 pdict_ent_add_persistent_change_listener_cb(const void *lid, const void *pl,
00199 void *a)
00200 {
00201 return _pdict_ent_add_persistent_change_listener((pdict_ent_t *)a,
00202 (pdict_persistent_listener_t *)pl);
00203 }
00204
00205 static int
00206 _pdict_ent_add_persistent_change_listeners(pdict_t *pd, pdict_ent_t *pde)
00207 {
00208 if (!plist_walk(pd->pd_persistent_listeners, pdict_ent_add_persistent_change_listener_cb, pde)) {
00209 plist_walk(pd->pd_persistent_listeners, pdict_ent_remove_persistent_change_listener_cb, pde);
00210 pu_log(PUL_WARN, 0, "Failed to add persistent change listener in _pdict_ent_add_persistent_change_listeners.");
00211 return 0;
00212 }
00213 return 1;
00214 }
00215
00216 static int
00217 pdict_ent_remove_persistent_change_listener_dcb(pdict_ent_t *pde, void *pl)
00218 {
00219 return _pdict_ent_remove_persistent_change_listener(pde,
00220 (pdict_persistent_listener_t *)pl);
00221 }
00222
00223 static int
00224 pdict_ent_add_persistent_change_listener_dcb(pdict_ent_t *pde, void *pl)
00225 {
00226 return _pdict_ent_add_persistent_change_listener(pde,
00227 (pdict_persistent_listener_t *)pl);
00228 }
00229
00230 static int
00231 _pdict_ent_add_persistent_change_listener(pdict_ent_t *pde,
00232 pdict_persistent_listener_t *pdpl)
00233 {
00234 int res;
00235
00236 if ((res = regexec(&pdpl->pdpl_regex, pde->pde_key, 0, NULL, 0)) != 0)
00237 {
00238 return res == REG_NOMATCH;
00239 }
00240 if (!_pdict_ent_add_change_listener(pde, pdpl->pdpl_l.pdl_notify, pdpl->pdpl_l.pdl_arg))
00241 {
00242 pu_log(PUL_WARN, 0, "Failed to add persistent change listener in _pdict_ent_add_persistent_change_listener.");
00243 return 0;
00244 }
00245 if (pdpl->pdpl_new)
00246 pdpl->pdpl_l.pdl_notify(pde->pde_key, pde->pde_val, PDR_CURRENT_VALUE, NULL, pdpl->pdpl_l.pdl_arg);
00247 return 1;
00248 }
00249
00250 static int
00251 _pdict_ent_remove_persistent_change_listener(pdict_ent_t *pde,
00252 pdict_persistent_listener_t *pl)
00253 {
00254 _pdict_ent_remove_change_listener(pde, pl->pdpl_l.pdl_notify,
00255 pl->pdpl_l.pdl_arg);
00256 return 1;
00257 }
00258
00259 int
00260 pdict_remove_persistent_change_listener(pdict_t *pd, int id)
00261 {
00262 pdict_persistent_listener_t *pdpl;
00263
00264 if (!plist_remove((void *)(size_t)id, &pd->pd_persistent_listeners, (void **)&pdpl) || !pdpl)
00265 {
00266 pu_log(PUL_WARN, 0, "Failed plist_remove in pdict_remove_persistent_change_listener.");
00267 return 0;
00268 }
00269 if (!_pdict_walk_int(pd, pdict_ent_remove_persistent_change_listener_dcb, pdpl))
00270 {
00271 pu_log(PUL_WARN, 0, "Failed _pdict_walk_int in pdict_remove_persistent_change_listener.");
00272 return 0;
00273 }
00274 regfree(&pdpl->pdpl_regex);
00275 free(pdpl); pdpl = NULL;
00276 return 1;
00277 }
00278
00279 int
00280 pdict_add_persistent_change_listener(pdict_t *pd, const char *kpat,
00281 pdl_notify_func_t notify, void *arg)
00282 {
00283 pdict_persistent_listener_t *pl;
00284 static int lid = 1;
00285
00286 if (!(pl = malloc(sizeof (*pl))))
00287 return 0;
00288 memset(pl, 0, sizeof (*pl));
00289 pl->pdpl_l.pdl_notify = notify;
00290 pl->pdpl_l.pdl_arg = arg;
00291 if (regcomp(&pl->pdpl_regex, kpat, REG_EXTENDED | REG_NOSUB) != 0) {
00292
00293 free(pl); pl = NULL;
00294 pu_log(PUL_WARN, 0, "Failed regcomp in pdict_add_persistent_change_listener.");
00295 return 0;
00296 }
00297
00298 plist_add((void *)(size_t)lid, pl, &pd->pd_persistent_listeners);
00299
00300 pl->pdpl_new = 1;
00301 if (!_pdict_walk_int(pd,
00302 pdict_ent_add_persistent_change_listener_dcb, pl)) {
00303 _pdict_walk_int(pd,
00304 pdict_ent_remove_persistent_change_listener_dcb, pl);
00305 plist_remove((void *)(size_t)lid, &pd->pd_persistent_listeners, NULL);
00306 regfree(&pl->pdpl_regex);
00307 free(pl); pl = NULL;
00308 pu_log(PUL_WARN, 0, "Failed _pdict_walk_int in pdict_add_persistent_change_listener.");
00309 return 0;
00310 }
00311 pl->pdpl_new = 0;
00312 return lid++;
00313 }
00314
00315
00316
00317
00318
00319 static int
00320 _pdict_ent_lookup(pdict_t *pd, const char *k, pdict_ent_t **e)
00321 {
00322 return ptree_contains((void *)&k, pd->pd_ents, pdecmp, (void **)e);
00323 }
00324
00325 int
00326 pdict_ent_lookup(pdict_t *pd, const char *k, const char **v)
00327 {
00328 pdict_ent_t *pde;
00329
00330 if (_pdict_ent_lookup(pd, k, &pde)) {
00331 if (v)
00332 *v = strdup(pde->pde_val);
00333 return 1;
00334 }
00335 return 0;
00336 }
00337
00338 static int
00339 pdict_ent_remove_change_listener_cb(const void *k, const void *v, void *a)
00340 {
00341 pdict_listener_t *l = (pdict_listener_t *)k;
00342 void **arg = (void **)a;
00343
00344 if (l->pdl_notify == (pdl_notify_func_t)arg[0] && l->pdl_arg == arg[1]) {
00345 arg[2] = l;
00346 return 0;
00347 }
00348 return 1;
00349 }
00350
00351 static int
00352 _pdict_ent_remove_change_listener(pdict_ent_t *pde, pdl_notify_func_t notify,
00353 void *a)
00354 {
00355 void *arg[3];
00356
00357 arg[0] = (void *)notify;
00358 arg[1] = a;
00359 arg[2] = NULL;
00360 plist_walk(pde->pde_listeners, pdict_ent_remove_change_listener_cb, arg);
00361 if (arg[2]) {
00362 plist_remove(arg[2], &pde->pde_listeners, NULL);
00363 free(arg[2]); arg[2] = NULL;
00364 return 1;
00365 }
00366 return 0;
00367 }
00368
00369 static int
00370 _pdict_ent_add_change_listener(pdict_ent_t *pde, pdl_notify_func_t notify,
00371 void *arg)
00372 {
00373 pdict_listener_t *l;
00374
00375 if (!(l = malloc(sizeof (*l))))
00376 return 0;
00377 memset(l, 0, sizeof (*l));
00378 l->pdl_notify = notify;
00379 l->pdl_arg = arg;
00380 if (!plist_add(l, 0, &pde->pde_listeners)) {
00381 free(l); l = NULL;
00382 pu_log(PUL_WARN, 0, "Failed plist_add in _pdict_ent_add_change_listener.");
00383 return 0;
00384 }
00385
00386 return 1;
00387 }
00388
00389 int
00390 pdict_ent_add_change_listener(pdict_t *pd, const char *k,
00391 pdl_notify_func_t notify, void *arg)
00392 {
00393 pdict_ent_t *pde;
00394
00395 if (!_pdict_ent_lookup(pd, k, &pde))
00396 return 0;
00397 return _pdict_ent_add_change_listener(pde, notify, arg);
00398 }
00399
00400 typedef struct {
00401 pdict_ent_t *penca_pde;
00402 pdict_reason_t penca_reason;
00403 const char *penca_ov;
00404 } pdict_ent_notify_cb_args_t;
00405
00406 static int
00407 pdict_ent_notify_cb(const void *v, const void *v0, void *a)
00408 {
00409 pdict_listener_t *pdl = (pdict_listener_t *)v;
00410 pdict_ent_notify_cb_args_t *penca = a;
00411
00412 pdl->pdl_notify(penca->penca_pde->pde_key, penca->penca_pde->pde_val,
00413 penca->penca_reason, penca->penca_ov, pdl->pdl_arg);
00414 return 1;
00415 }
00416
00417 static void
00418 _pdict_ent_notify(pdict_ent_t *pde, int reason, const char *ov)
00419 {
00420 pdict_ent_notify_cb_args_t penca = { pde, reason, ov };
00421
00422 plist_walk(pde->pde_listeners, pdict_ent_notify_cb, &penca);
00423 }
00424
00425 static ptree_walk_res_t
00426 pdict_walk_int_cb(const void *v, int level, void *a, void *pwra)
00427 {
00428 void **args = a;
00429
00430 return ((pdict_walk_int_func_t)args[0])((pdict_ent_t *)v, args[1]);
00431 }
00432
00433 static ptree_walk_res_t
00434 pdict_walk_cb(const void *v, int level, void *a, void *pwra)
00435 {
00436 pdict_ent_t *pde = (pdict_ent_t *)v;
00437 void **args = a;
00438
00439 return ((pdict_walk_func_t)args[0])(pde->pde_key, pde->pde_val,
00440 args[1]);
00441 }
00442
00443 static int
00444 _pdict_walk_int(pdict_t *pd, pdict_walk_int_func_t w, void *arg)
00445 {
00446 void *args[2] = { (void *)w, arg };
00447
00448 return ptree_walk(pd->pd_ents, PTREE_INORDER, pdict_walk_int_cb, pdecmp, args);
00449 }
00450
00451 int
00452 pdict_walk(pdict_t *pd, pdict_walk_func_t w, void *arg)
00453 {
00454 void *args[2] = { (void *)w, arg };
00455
00456 return ptree_walk(pd->pd_ents, PTREE_INORDER, pdict_walk_cb, NULL, args);
00457 }
00458
00459 int
00460 pdict_ent_remove_change_listener(pdict_t *pd, const char *k,
00461 pdl_notify_func_t nf, void *arg)
00462 {
00463 pdict_ent_t *e;
00464 int res;
00465
00466 if (!(res = _pdict_ent_lookup(pd, k, &e)))
00467 return 0;
00468 return _pdict_ent_remove_change_listener(e, nf, arg);
00469 }
00470
00471 const char *
00472 pdict_reason_str(pdict_reason_t r)
00473 {
00474 switch (r) {
00475 case PDR_VALUE_CHANGED:
00476 return "changed";
00477 case PDR_ENTRY_ADDED:
00478 return "added";
00479 case PDR_ENTRY_REMOVING:
00480 return "removing";
00481 case PDR_CURRENT_VALUE:
00482 return "current";
00483 default:
00484 return "?";
00485 }
00486 }
00487
00488 pdict_reason_t
00489 pdict_reason_from_str(const char *s)
00490 {
00491 if (strcmp(s, "changed") == 0)
00492 return PDR_VALUE_CHANGED;
00493 if (strcmp(s, "current") == 0)
00494 return PDR_CURRENT_VALUE;
00495 if (strcmp(s, "added") == 0)
00496 return PDR_ENTRY_ADDED;
00497 if (strcmp(s, "removing") == 0)
00498 return PDR_ENTRY_REMOVING;
00499 return 0;
00500 }