1 /* sdb - MIT - Copyright 2019 - thestr4ng3r */
2
3 #include "sdb.h"
4
sdb_diff_format(char * str,int size,const SdbDiff * diff)5 SDB_API int sdb_diff_format(char *str, int size, const SdbDiff *diff) {
6 int r = 0;
7 #define APPENDF(...) do { \
8 int sr = snprintf (str, size, __VA_ARGS__); \
9 if (sr < 0) { \
10 return sr; \
11 } \
12 r += sr; \
13 if (sr >= size) { \
14 /* no space left, only measure from now on */ \
15 str = NULL; \
16 size = 0; \
17 } else { \
18 str += sr; \
19 size -= sr; \
20 } \
21 } while(0)
22
23 APPENDF ("%c%s ", diff->add ? '+' : '-', diff->v ? " " : "NS");
24
25 SdbListIter *it;
26 const char *component;
27 ls_foreach (diff->path, it, component) {
28 APPENDF ("%s/", component);
29 }
30
31 if (diff->v) {
32 APPENDF ("%s=%s", diff->k, diff->v);
33 } else {
34 APPENDF ("%s", diff->k);
35 }
36
37 #undef APPENDF
38 return r;
39 }
40
41 typedef struct sdb_diff_ctx_t {
42 Sdb *a;
43 Sdb *b;
44 bool equal;
45 SdbList *path;
46 SdbDiffCallback cb;
47 void *cb_user;
48 } SdbDiffCtx;
49
50 #define DIFF(ctx, c, ret) do { \
51 (ctx)->equal = false; \
52 if ((ctx)->cb) { \
53 c \
54 } else { \
55 /* we already know it's not equal and don't care about the rest of the diff */ \
56 return ret; \
57 } \
58 } while(0)
59
60
sdb_diff_report_ns(SdbDiffCtx * ctx,SdbNs * ns,bool add)61 static void sdb_diff_report_ns(SdbDiffCtx *ctx, SdbNs *ns, bool add) {
62 SdbDiff diff = { ctx->path, ns->name, NULL, add };
63 ctx->cb (&diff, ctx->cb_user);
64 }
65
sdb_diff_report_kv(SdbDiffCtx * ctx,const char * k,const char * v,bool add)66 static void sdb_diff_report_kv(SdbDiffCtx *ctx, const char *k, const char *v, bool add) {
67 SdbDiff diff = { ctx->path, k, v, add };
68 ctx->cb (&diff, ctx->cb_user);
69 }
70
71 typedef struct sdb_diff_kv_cb_ctx {
72 SdbDiffCtx *ctx;
73 bool add;
74 } SdbDiffKVCbCtx;
75
sdb_diff_report_kv_cb(void * user,const char * k,const char * v)76 static bool sdb_diff_report_kv_cb(void *user, const char *k, const char *v) {
77 const SdbDiffKVCbCtx *ctx = user;
78 sdb_diff_report_kv (ctx->ctx, k, v, ctx->add);
79 return true;
80 }
81
82 /**
83 * just report everything from sdb to buf with prefix
84 */
sdb_diff_report(SdbDiffCtx * ctx,Sdb * sdb,bool add)85 static void sdb_diff_report(SdbDiffCtx *ctx, Sdb *sdb, bool add) {
86 SdbListIter *it;
87 SdbNs *ns;
88 ls_foreach (sdb->ns, it, ns) {
89 sdb_diff_report_ns (ctx, ns, add);
90 ls_push (ctx->path, ns->name);
91 sdb_diff_report (ctx, ns->sdb, add);
92 ls_pop (ctx->path);
93 }
94 SdbDiffKVCbCtx cb_ctx = { ctx, add };
95 sdb_foreach (sdb, sdb_diff_report_kv_cb, &cb_ctx);
96 }
97
sdb_diff_kv_cb(void * user,const char * k,const char * v)98 static bool sdb_diff_kv_cb(void *user, const char *k, const char *v) {
99 const SdbDiffKVCbCtx *ctx = user;
100 Sdb *other = ctx->add ? ctx->ctx->a : ctx->ctx->b;
101 const char *other_val = sdb_const_get (other, k, NULL);
102 if (!other_val || !*other_val) {
103 DIFF (ctx->ctx,
104 sdb_diff_report_kv (ctx->ctx, k, v, ctx->add);
105 , false);
106 } else if (!ctx->add && strcmp (v, other_val) != 0) {
107 DIFF (ctx->ctx,
108 sdb_diff_report_kv (ctx->ctx, k, v, false);
109 sdb_diff_report_kv (ctx->ctx, k, other_val, true);
110 , false);
111 }
112 return true;
113 }
114
sdb_diff_ctx(SdbDiffCtx * ctx)115 static void sdb_diff_ctx(SdbDiffCtx *ctx) {
116 SdbListIter *it;
117 SdbNs *ns;
118 ls_foreach (ctx->a->ns, it, ns) {
119 Sdb *b_ns = sdb_ns (ctx->b, ns->name, false);
120 if (!b_ns) {
121 DIFF (ctx,
122 sdb_diff_report_ns (ctx, ns, false);
123 ls_push (ctx->path, ns->name);
124 sdb_diff_report (ctx, ns->sdb, false);
125 ls_pop (ctx->path);
126 ,);
127 continue;
128 }
129 Sdb *a = ctx->a;
130 Sdb *b = ctx->b;
131 ctx->a = ns->sdb;
132 ctx->b = b_ns;
133 ls_push (ctx->path, ns->name);
134 sdb_diff_ctx (ctx);
135 ls_pop (ctx->path);
136 ctx->a = a;
137 ctx->b = b;
138 }
139 ls_foreach (ctx->b->ns, it, ns) {
140 if (!sdb_ns (ctx->a, ns->name, false)) {
141 DIFF (ctx,
142 sdb_diff_report_ns (ctx, ns, true);
143 ls_push (ctx->path, ns->name);
144 sdb_diff_report (ctx, ns->sdb, true);
145 ls_pop (ctx->path);
146 ,);
147 }
148 }
149 SdbDiffKVCbCtx kv_ctx = { ctx, false };
150 if (!sdb_foreach (ctx->a, sdb_diff_kv_cb, &kv_ctx)) {
151 return;
152 }
153 kv_ctx.add = true;
154 sdb_foreach (ctx->b, sdb_diff_kv_cb, &kv_ctx);
155 }
156
sdb_diff(Sdb * a,Sdb * b,SdbDiffCallback cb,void * cb_user)157 SDB_API bool sdb_diff(Sdb *a, Sdb *b, SdbDiffCallback cb, void *cb_user) {
158 SdbDiffCtx ctx;
159 ctx.a = a;
160 ctx.b = b;
161 ctx.equal = true;
162 ctx.cb = cb;
163 ctx.cb_user = cb_user;
164 ctx.path = ls_new ();
165 if (!ctx.path) {
166 return false;
167 }
168 sdb_diff_ctx (&ctx);
169 ls_free (ctx.path);
170 return ctx.equal;
171 }
172