WvStreams
unireplicategen.cc
1/*
2 * Worldvisions Weaver Software:
3 * Copyright (C) 2002 Net Integration Technologies, Inc.
4 *
5 * A UniConf generator that replicates multiple generators, prioritized
6 * by order.
7 */
8#include "uniconf.h"
9#include "unireplicategen.h"
10#include "wvmoniker.h"
11#include "wvstringlist.h"
12#include "wvtclstring.h"
13#include "wvlinkerhack.h"
14
15WV_LINK(UniReplicateGen);
16
17
18#if 0
19#define DPRINTF(format, args...) fprintf(stderr, format ,##args);
20#else
21#define DPRINTF if (0) printf
22#endif
23
24
25static IUniConfGen *creator(WvStringParm s, IObject *_obj)
26{
27 IUniConfGenList gens;
28
29 DPRINTF("encoded_monikers = %s\n", s.cstr());
30 WvStringList monikers;
31 wvtcl_decode(monikers, s);
32 DPRINTF("monikers = %s\n", monikers.join(",").cstr());
33
34 WvStringList::Iter i(monikers);
35 for (i.rewind(); i.next(); )
36 {
37 if (_obj) _obj->addRef();
38 IUniConfGen *gen = wvcreate<IUniConfGen>(*i, _obj);
39 if (gen)
40 gens.append(gen, false);
41 }
42 if (_obj) _obj->release();
43
44 return new UniReplicateGen(gens);
45}
46
47static WvMoniker<IUniConfGen> reg("replicate", creator);
48
49
50/***** UniReplicateGen *****/
51
52UniReplicateGen::UniReplicateGen() : processing_callback(false)
53{
54}
55
56
57UniReplicateGen::UniReplicateGen(const IUniConfGenList &_gens,
58 bool auto_free) : processing_callback(false)
59{
60 IUniConfGenList::Iter i(_gens);
61
62 for (i.rewind(); i.next(); )
63 {
64 Gen *gen = new Gen(i.ptr(), auto_free);
65 if (gen)
66 {
67 gens.append(gen, true);
68 gen->gen->add_callback(this,
69 wv::bind(&UniReplicateGen::deltacallback,
70 this, gen, _1, _2));
71 }
72 }
73
74 replicate();
75}
76
77
78UniReplicateGen::~UniReplicateGen()
79{
80 GenList::Iter i(gens);
81 for (i.rewind(); i.next(); )
82 i->gen->del_callback(this);
83}
84
85
86void UniReplicateGen::prepend(IUniConfGen *_gen, bool auto_free)
87{
88 Gen *gen = new Gen(_gen, auto_free);
89 if (gen)
90 {
91 gens.prepend(gen, true);
92 gen->gen->add_callback(this, wv::bind(&UniReplicateGen::deltacallback,
93 this, gen, _1, _2));
94
95 replicate();
96 }
97}
98
99
100void UniReplicateGen::append(IUniConfGen *_gen, bool auto_free)
101{
102 Gen *gen = new Gen(_gen, auto_free);
103 if (gen)
104 {
105 gens.append(gen, true);
106 gen->gen->add_callback(this, wv::bind(&UniReplicateGen::deltacallback,
107 this, gen, _1, _2));
108
109 replicate();
110 }
111}
112
113
115{
116 return first_ok() != NULL;
117}
118
119
121{
122 bool result = true;
123
124 replicate_if_any_have_become_ok();
125
126 GenList::Iter i(gens);
127 for (i.rewind(); i.next(); )
128 {
129 if (!i->gen->refresh())
130 result = false;
131 }
132
133 return result;
134}
135
136
138{
139 replicate_if_any_have_become_ok();
140
141 GenList::Iter i(gens);
142 for (i.rewind(); i.next(); )
143 {
144 i->gen->commit();
145 }
146}
147
148
149void UniReplicateGen::deltacallback(Gen *src_gen, const UniConfKey &key,
150 WvStringParm value)
151{
152 DPRINTF("UniReplicateGen::deltacallback(%s, %s)\n",
153 key.printable().cstr(), value.cstr());
154
155 if (!processing_callback)
156 {
157 DPRINTF("UniReplicateGen::deltacallback(): !processing_callback\n");
158
159 processing_callback = true;
160
161 GenList::Iter j(gens);
162 for (j.rewind(); j.next(); )
163 {
164 if (!j->isok())
165 continue;
166
167 if (j.ptr() != src_gen)
168 {
169 DPRINTF("UniReplicateGen::deltacallback: %p->set(%s, %s)\n",
170 j.ptr(), key.printable().cstr(), value.cstr());
171 j->gen->set(key, value);
172 }
173 }
174
175 delta(key, value);
176
177 processing_callback = false;
178 }
179 else
180 {
181 DPRINTF("UniReplicateGen::deltacallback(): processing_callback\n");
182 }
183}
184
185
187{
188 DPRINTF("UniReplicateGen::set(%s, %s)\n",
189 key.printable().cstr(), value.cstr());
190
191 replicate_if_any_have_become_ok();
192
193 Gen *first = first_ok();
194 if (first)
195 first->gen->set(key, value);
196 else
197 DPRINTF("UniReplicateGen::set: first == NULL\n");
198}
199
200
201void UniReplicateGen::setv(const UniConfPairList &pairs)
202{
203 DPRINTF("UniReplicateGen::setv\n");
204
205 replicate_if_any_have_become_ok();
206
207 Gen *first = first_ok();
208 if (first)
209 first->gen->setv(pairs);
210 else
211 DPRINTF("UniReplicateGen::setv: first == NULL\n");
212}
213
214
216{
217 for (;;)
218 {
219 replicate_if_any_have_become_ok();
220
221 Gen *first = first_ok();
222 if (first)
223 {
224 WvString result = first->gen->get(key);
225
226 // It's possible that first has become !isok(); we must
227 // take care of this case carefully
228 if (!result && !first->isok())
229 {
230 Gen *new_first = first_ok();
231 if (new_first == first)
232 return result;
233 first = new_first;
234 }
235 else
236 return result;
237 }
238 else
239 return WvString::null;
240 }
241}
242
243
245{
246 replicate_if_any_have_become_ok();
247
248 Gen *first = first_ok();
249 if (first)
250 return first->gen->iterator(key);
251 else
252 return NULL;
253}
254
255
256UniReplicateGen::Gen *UniReplicateGen::first_ok() const
257{
258 GenList::Iter j(gens);
259 for (j.rewind(); j.next(); )
260 {
261 if (j->isok())
262 return j.ptr();
263 }
264
265 return NULL;
266}
267
268
269void UniReplicateGen::replicate(const UniConfKey &key)
270{
271 DPRINTF("UniReplicateGen::replicate(%s)\n", key.printable().cstr());
272
273 hold_delta();
274
275 Gen *first = first_ok();
276
277 GenList::Iter j(gens);
278 for (j.rewind(); j.next(); )
279 {
280 DPRINTF("UniReplicateGen::replicate: %p\n", j.ptr());
281
282 if (!j->isok())
283 {
284 DPRINTF("UniReplicateGen::replicate: !isok()\n");
285 continue;
286 }
287
288 UniConfGen::Iter *i = j->gen->recursiveiterator(key);
289 if (!i)
290 {
291 DPRINTF("UniReplicateGen::replicate: no iterator\n");
292 continue;
293 }
294
295 for (i->rewind(); i->next(); )
296 {
297 DPRINTF("UniReplicateGen::replicate: key=%s, value=%s\n",
298 i->key().printable().cstr(), i->value().cstr());
299
300 if (j.ptr() == first)
301 {
302 DPRINTF("UniReplicateGen::replicate: deltacallback()\n");
303 deltacallback(first, i->key(), i->value());
304 }
305 else
306 {
307 if (!first->gen->exists(i->key()))
308 {
309 DPRINTF("UniReplicateGen::replicate: !exists()\n");
310 first->gen->set(i->key(), i->value());
311 }
312 else
313 {
314 DPRINTF("UniReplicateGen::replicate: exists()\n");
315 }
316 }
317 }
318
319 delete i;
320 }
321
322 unhold_delta();
323
324 DPRINTF("UniReplicateGen::replicate: done\n");
325}
326
327void UniReplicateGen::replicate_if_any_have_become_ok()
328{
329 bool should_replicate = false;
330
331 GenList::Iter j(gens);
332 for (j.rewind(); j.next(); )
333 {
334 if (!j->was_ok && j->gen->isok())
335 {
336 j->was_ok = true;
337
338 should_replicate = true;
339 }
340 }
341
342 if (should_replicate)
343 {
344 DPRINTF("UniReplicateGen::replicate_if_any_have_become_ok: replicating\n");
345 replicate();
346 }
347}
348
The basic interface which is included by all other XPLC interfaces and objects.
Definition: IObject.h:65
virtual unsigned int addRef()=0
Indicate you are using this object.
virtual unsigned int release()=0
Indicate that you are finished using this object.
An abstract data container that backs a UniConf tree.
Definition: uniconfgen.h:40
An abstract iterator over keys and values in a generator.
Definition: uniconfgen.h:324
virtual bool next()=0
Seeks to the next element in the sequence.
virtual WvString value() const =0
Returns the value of the current key.
virtual void rewind()=0
Rewinds the iterator.
virtual UniConfKey key() const =0
Returns the current key.
void hold_delta()
Pauses notifications until matched with a call to unhold_delta().
Definition: uniconfgen.cc:32
void unhold_delta()
Resumes notifications when each hold_delta() has been matched.
Definition: uniconfgen.cc:38
void delta(const UniConfKey &key, WvStringParm value)
Call this when a key's value or children have possibly changed.
Definition: uniconfgen.cc:77
Represents a UniConf key which is a path in a hierarchy structured much like the traditional Unix fil...
Definition: uniconfkey.h:39
WvString printable() const
Returns the canonical string representation of the path.
Definition: uniconfkey.cc:212
A UniConf generator that replicates generators between an ordered list of inner generators,...
virtual Iter * iterator(const UniConfKey &key)
Returns an iterator over the children of the specified key.
virtual void commit()
Commits any changes.
virtual bool refresh()
Refreshes information about a key recursively.
virtual WvString get(const UniConfKey &key)
Fetches a string value for a key from the registry.
virtual void setv(const UniConfPairList &pairs)
Stores multiple key-value pairs into the registry.
virtual bool isok()
Determines if the generator is usable and working properly.
virtual void set(const UniConfKey &key, WvStringParm value)
Stores a string value for a key into the registry.
A WvFastString acts exactly like a WvString, but can take (const char *) strings without needing to a...
Definition: wvstring.h:94
const char * cstr() const
return a (const char *) for this string.
Definition: wvstring.h:267
A type-safe version of WvMonikerBase that lets you provide create functions for object types other th...
Definition: wvmoniker.h:62
This is a WvList of WvStrings, and is a really handy way to parse strings.
Definition: wvstringlist.h:28
WvString join(const char *joinchars=" ") const
concatenates all elements of the list seperating on joinchars
Definition: wvstringlist.cc:14
WvString is an implementation of a simple and efficient printable-string class.
Definition: wvstring.h:330
Functions to handle "tcl-style" strings and lists.
void wvtcl_decode(WvList< WvString > &l, WvStringParm _s, const WvStringMask &splitchars=WVTCL_SPLITCHARS, bool do_unescape=true)
split a tcl-style list.
Definition: wvtclstring.cc:386