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 
15 WV_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 
25 static 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 
47 static WvMoniker<IUniConfGen> reg("replicate", creator);
48 
49 
50 /***** UniReplicateGen *****/
51 
52 UniReplicateGen::UniReplicateGen() : processing_callback(false)
53 {
54 }
55 
56 
57 UniReplicateGen::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 
78 UniReplicateGen::~UniReplicateGen()
79 {
80  GenList::Iter i(gens);
81  for (i.rewind(); i.next(); )
82  i->gen->del_callback(this);
83 }
84 
85 
86 void 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 
100 void 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 
149 void 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 
186 void UniReplicateGen::set(const UniConfKey &key, WvStringParm value)
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 
201 void 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 
256 UniReplicateGen::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 
269 void 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 
327 void 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 
UniConfGen::Iter::value
virtual WvString value() const =0
Returns the value of the current key.
UniReplicateGen
A UniConf generator that replicates generators between an ordered list of inner generators,...
Definition: unireplicategen.h:26
wvtclstring.h
UniReplicateGen::set
virtual void set(const UniConfKey &key, WvStringParm value)
Stores a string value for a key into the registry.
Definition: unireplicategen.cc:186
UniConfGen::Iter::key
virtual UniConfKey key() const =0
Returns the current key.
UniConfKey::printable
WvString printable() const
Returns the canonical string representation of the path.
Definition: uniconfkey.cc:212
UniConfGen::unhold_delta
void unhold_delta()
Resumes notifications when each hold_delta() has been matched.
Definition: uniconfgen.cc:38
WvString
WvString is an implementation of a simple and efficient printable-string class.
Definition: wvstring.h:329
IUniConfGen
An abstract data container that backs a UniConf tree.
Definition: uniconfgen.h:39
UniReplicateGen::setv
virtual void setv(const UniConfPairList &pairs)
Stores multiple key-value pairs into the registry.
Definition: unireplicategen.cc:201
UniReplicateGen::refresh
virtual bool refresh()
Refreshes information about a key recursively.
Definition: unireplicategen.cc:120
WvFastString::cstr
const char * cstr() const
return a (const char *) for this string.
Definition: wvstring.h:267
WvStringList::join
WvString join(const char *joinchars=" ") const
concatenates all elements of the list seperating on joinchars
Definition: wvstringlist.cc:14
UniReplicateGen::get
virtual WvString get(const UniConfKey &key)
Fetches a string value for a key from the registry.
Definition: unireplicategen.cc:215
UniConfKey
Represents a UniConf key which is a path in a hierarchy structured much like the traditional Unix fil...
Definition: uniconfkey.h:38
WvMoniker
A type-safe version of WvMonikerBase that lets you provide create functions for object types other th...
Definition: wvmoniker.h:61
IObject::release
virtual unsigned int release()=0
Indicate that you are finished using this object.
UniReplicateGen::commit
virtual void commit()
Commits any changes.
Definition: unireplicategen.cc:137
UniConfGen::delta
void delta(const UniConfKey &key, WvStringParm value)
Call this when a key's value or children have possibly changed.
Definition: uniconfgen.cc:77
IObject
Definition: IObject.h:65
UniConfGen::Iter::rewind
virtual void rewind()=0
Rewinds the iterator.
UniConfGen::Iter::next
virtual bool next()=0
Seeks to the next element in the sequence.
UniReplicateGen::isok
virtual bool isok()
Determines if the generator is usable and working properly.
Definition: unireplicategen.cc:114
WvStringList
This is a WvList of WvStrings, and is a really handy way to parse strings.
Definition: wvstringlist.h:27
wvtcl_decode
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
IObject::addRef
virtual unsigned int addRef()=0
Indicate you are using this object.
UniConfGen::hold_delta
void hold_delta()
Pauses notifications until matched with a call to unhold_delta().
Definition: uniconfgen.cc:32
UniReplicateGen::iterator
virtual Iter * iterator(const UniConfKey &key)
Returns an iterator over the children of the specified key.
Definition: unireplicategen.cc:244
UniConfGen::Iter
An abstract iterator over keys and values in a generator.
Definition: uniconfgen.h:323