WvStreams
uniconfroot.cc
1 /*
2  * Worldvisions Weaver Software:
3  * Copyright (C) 1997-2002 Net Integration Technologies, Inc.
4  *
5  * Defines the root management class for UniConf. To create any kind of
6  * UniConf tree, you'll need one of these.
7  */
8 #include "uniconfroot.h"
9 #include "wvlinkerhack.h"
10 
11 WV_LINK_TO(UniGenHack);
12 
13 
15  UniConf(this),
16  watchroot(NULL)
17 {
18  mounts.add_callback(this, wv::bind(&UniConfRoot::gen_callback, this,
19  _1, _2));
20 }
21 
22 
23 UniConfRoot::UniConfRoot(WvStringParm moniker, bool refresh):
24  UniConf(this),
25  watchroot(NULL)
26 {
27  mounts.mount("/", moniker, refresh);
28  mounts.add_callback(this, wv::bind(&UniConfRoot::gen_callback, this,
29  _1, _2));
30 }
31 
32 
34  UniConf(this),
35  watchroot(NULL)
36 {
37  mounts.mountgen("/", gen, refresh);
38  mounts.add_callback(this, wv::bind(&UniConfRoot::gen_callback, this,
39  _1, _2));
40 }
41 
42 
43 // make sure the given subtree of callback information is empty
44 static bool watchout(UniWatchInfoTree *t)
45 {
46  bool fail = false;
47 
49  for (i.rewind(); i.next(); )
50  {
51  UniWatchInfoTree *w = i.ptr();
52 
53  if (w->haschildren())
54  if (watchout(w))
55  fail = true;
56 
57  if (!w->watches.isempty())
58  {
59  fail = true;
60  if (1)
61  fprintf(stderr, "Remaining watch: '%s' (%zd)\n",
62  w->fullkey().printable().cstr(), w->watches.count());
63  }
64  }
65 
66  return fail;
67 }
68 
69 
71 {
72  // first, unmount everything. Some of the mounts might have waiting
73  // callbacks. (I hope not, but... things like UniUnwrapGen might get
74  // confusing.)
75  mounts.zap();
76 
77  // if the list of callbacks is non-empty, someone is either very buggy
78  // (they disappeared without deleting their callback, so they could cause
79  // crashes), or they're not getting what they expected (we disappeared
80  // before they did, so they won't be getting their callback).
81  assert(!watchout(&watchroot));
82 
83  mounts.del_callback(this);
84 }
85 
86 
87 void UniConfRoot::add_callback(void *cookie, const UniConfKey &key,
88  const UniConfCallback &callback, bool recurse)
89 {
90  UniWatchInfo *w = new UniWatchInfo(cookie, recurse, callback);
91 
92  UniWatchInfoTree *node = &watchroot;
93 
95  for (i.rewind(); i.next(); )
96  {
97  UniWatchInfoTree *prev = node;
98  node = node->findchild(i());
99  if (!node)
100  node = new UniWatchInfoTree(prev, i());
101  }
102  node->watches.append(w, true);
103 }
104 
105 
106 void UniConfRoot::del_callback(void *cookie, const UniConfKey &key,
107  bool recurse)
108 {
109  UniWatchInfoTree *node = watchroot.find(key);
110  if (node)
111  {
112  UniWatchInfoList::Iter i(node->watches);
113  for (i.rewind(); i.next(); )
114  {
115  // remove the watch if it matches
116  if (i->cookie == cookie && i->recurse == recurse)
117  {
118  i.xunlink();
119  break;
120  }
121  }
122  // prune the branch if needed
123  prune(node);
124  }
125 }
126 
127 
128 void UniConfRoot::add_setbool(const UniConfKey &key, bool *flag, bool recurse)
129 {
130  add_callback(flag, key, wv::bind(&UniConfRoot::setbool_callback, flag,
131  _1, _2),
132  recurse);
133 }
134 
135 
136 void UniConfRoot::del_setbool(const UniConfKey &key, bool *flag, bool recurse)
137 {
138  del_callback(flag, key, recurse);
139 }
140 
141 
142 void UniConfRoot::check(UniWatchInfoTree *node,
143  const UniConfKey &key, int segleft)
144 {
145  UniWatchInfoList::Iter i(node->watches);
146  for (i.rewind(); i.next(); )
147  {
148  if (!i->recursive() && segleft > 0)
149  continue;
150 
151  i->notify(UniConf(this, key.removelast(segleft)), key.last(segleft));
152  }
153 }
154 
155 
156 void UniConfRoot::deletioncheck(UniWatchInfoTree *node, const UniConfKey &key)
157 {
158  UniWatchInfoTree::Iter i(*node);
159  for (i.rewind(); i.next(); )
160  {
161  UniWatchInfoTree *w = i.ptr();
162  UniConfKey subkey(key, w->key());
163 
164  // pretend that we wiped out just this key
165  check(w, subkey, 0);
166  deletioncheck(w, subkey);
167  }
168 }
169 
170 
171 void UniConfRoot::prune(UniWatchInfoTree *node)
172 {
173  while (node != & watchroot && ! node->isessential())
174  {
175  UniWatchInfoTree *next = node->parent();
176  delete node;
177  node = next;
178  }
179 }
180 
181 
182 void UniConfRoot::gen_callback(const UniConfKey &key, WvStringParm value)
183 {
184  hold_delta();
185  UniWatchInfoTree *node = & watchroot;
186  int segs = key.numsegments();
187 
188  // check root node
189  check(node, key, segs);
190 
191  // look for watches on key and its ancestors
192  for (int s = 0; s < segs; )
193  {
194  node = node->findchild(key.segment(s));
195  s++;
196  if (!node)
197  goto done; // no descendents so we can stop
198  check(node, key, segs - s);
199  }
200 
201  // look for watches on descendents of key if node was deleted
202  if (value.isnull())
203  deletioncheck(node, key);
204 
205 done:
206  unhold_delta();
207 }
UniConf::refresh
bool refresh() const
Refreshes information about this key recursively.
Definition: uniconf.cc:119
UniMountGen::mount
virtual IUniConfGen * mount(const UniConfKey &key, WvStringParm moniker, bool refresh)
Mounts a generator at a key using a moniker.
Definition: unimountgen.cc:176
UniConfRoot::del_setbool
void del_setbool(const UniConfKey &key, bool *flag, bool recurse=true)
Cancels notification requested using add_setbool().
Definition: uniconfroot.cc:136
UniConfRoot::add_callback
void add_callback(void *cookie, const UniConfKey &key, const UniConfCallback &callback, bool recurse=true)
Requests notification when any of the keys covered by the recursive depth specification change by inv...
Definition: uniconfroot.cc:87
UniConfRoot::UniConfRoot
UniConfRoot()
Creates an empty UniConf tree with no mounted stores.
Definition: uniconfroot.cc:14
UniConfKey::removelast
UniConfKey removelast(int n=1) const
Returns the path formed by removing the last n segments of this path.
Definition: uniconfkey.h:346
UniWatchInfo
Definition: uniconfroot.h:19
UniConf
UniConf instances function as handles to subtrees of a UniConf tree and expose a high-level interface...
Definition: uniconf.h:50
UniConfKey::printable
WvString printable() const
Returns the canonical string representation of the path.
Definition: uniconfkey.cc:212
UniConfTree::findchild
Sub * findchild(const UniConfKey &key) const
Finds the direct child node with the specified key.
Definition: uniconftree.h:71
UniConfRoot::setbool_callback
static void setbool_callback(bool *flag, const UniConf &, const UniConfKey &)
Internal callback for setbool style notifications.
Definition: uniconfroot.h:157
UniHashTreeBase::key
const UniConfKey & key() const
Returns the key field.
Definition: unihashtree.h:40
UniWatchInfoTree
Definition: uniconfroot.h:48
UniConfKey::Iter
An iterator over the segments of a key.
Definition: uniconfkey.h:463
UniHashTreeBase::Iter
Definition: unihashtree.h:78
WvFastString::cstr
const char * cstr() const
return a (const char *) for this string.
Definition: wvstring.h:267
UniConfKey
Represents a UniConf key which is a path in a hierarchy structured much like the traditional Unix fil...
Definition: uniconfkey.h:38
UniMountGen::mountgen
virtual IUniConfGen * mountgen(const UniConfKey &key, IUniConfGen *gen, bool refresh)
Mounts a generator at a key.
Definition: unimountgen.cc:191
UniConfTree::parent
Sub * parent() const
Returns a pointer to the parent node, or NULL if there is none.
Definition: uniconftree.h:40
UniConfGen
A default implementation of IUniConfGen, providing various handy features that save trouble when impl...
Definition: uniconfgen.h:199
UniWatchInfoTree::isessential
bool isessential()
Returns true if the node should not be pruned.
Definition: uniconfroot.h:58
UniConfTree::fullkey
UniConfKey fullkey(const Sub *ancestor=NULL) const
Returns full path of this node relative to an ancestor.
Definition: uniconftree.h:55
UniConfRoot::del_callback
void del_callback(void *cookie, const UniConfKey &key, bool recurse=true)
Cancels notification requested using add_callback().
Definition: uniconfroot.cc:106
UniConfKey::segment
UniConfKey segment(int n) const
Returns the specified segment of the path.
Definition: uniconfkey.h:297
UniHashTreeBase::haschildren
bool haschildren() const
Returns true if the node has children.
Definition: unihashtree.cc:114
UniConf::hold_delta
void hold_delta()
Pauses notifications until matched with a call to unhold_delta().
Definition: uniconf.cc:193
UniConfTree::find
Sub * find(const UniConfKey &key) const
Finds the sub-node with the specified key.
Definition: uniconftree.h:62
UniConfRoot::~UniConfRoot
~UniConfRoot()
Destroys the UniConf tree along with all uncommitted data.
Definition: uniconfroot.cc:70
UniConfKey::last
UniConfKey last(int n=1) const
Returns the path formed by the n last segments of this path.
Definition: uniconfkey.h:324
UniConfRoot::add_setbool
void add_setbool(const UniConfKey &key, bool *flag, bool recurse=true)
Requests notification when any of the keys covered by the recursive depth specification change by set...
Definition: uniconfroot.cc:128
UniConfKey::numsegments
int numsegments() const
Returns the number of segments in this path.
Definition: uniconfkey.h:287
UniConfGen::add_callback
virtual void add_callback(void *cookie, const UniConfGenCallback &callback)
Adds a callback for change notification.
Definition: uniconfgen.cc:158
UniConf::key
UniConfKey key() const
Returns the path of this node relative to its parent.
Definition: uniconf.h:111
UniConfGen::del_callback
virtual void del_callback(void *cookie)
Removes a callback for change notification.
Definition: uniconfgen.cc:165
UniConf::unhold_delta
void unhold_delta()
Resumes notifications when each hold_delta() has been matched.
Definition: uniconf.cc:199