WvStreams
unitempgen.cc
1 /*
2  * Worldvisions Weaver Software:
3  * Copyright (C) 2002-2005 Net Integration Technologies, Inc.
4  *
5  * A UniConf generator that stores keys in memory.
6  */
7 #include "unitempgen.h"
8 #include "wvmoniker.h"
9 #include "wvlog.h"
10 #include "wvstringcache.h"
11 #include "unilistiter.h"
12 #include "wvlinkerhack.h"
13 
14 WV_LINK(UniTempGen);
15 
16 static IUniConfGen *creator(WvStringParm, IObject*)
17 {
18  return new UniTempGen();
19 }
20 
21 static WvMoniker<IUniConfGen> reg("temp", creator);
22 
23 
24 /***** UniTempGen *****/
25 
26 UniTempGen::UniTempGen()
27  : root(NULL)
28 {
29 }
30 
31 
32 UniTempGen::~UniTempGen()
33 {
34  delete root;
35 }
36 
37 
39 {
40  if (root)
41  {
42  // Look for an empty section at the end.
43  if (!key.isempty() && key.last().isempty())
44  return WvString::null;
45  UniConfValueTree *node = root->find(key);
46  if (node)
47  return node->value();
48  }
49  return WvString::null;
50 }
51 
52 void UniTempGen::notify_deleted(const UniConfValueTree *node, void *)
53 {
54  delta(node->fullkey(), WvString::null);
55 }
56 
57 void UniTempGen::set(const UniConfKey &_key, WvStringParm _value)
58 {
59  WvString value(scache.get(_value));
60 
61  hold_delta();
62  UniConfKey key = _key;
63  // FIXME: Use key.hastrailingslash(), it's shorter and easier and faster
64  bool trailing_slash = false;
65  if (!key.isempty())
66  {
67  // Look for an empty section at the end.
68  UniConfKey last = key;
69  key = last.pop(last.numsegments() - 1);
70  if (last.isempty())
71  trailing_slash = true;
72  else
73  key = _key;
74  }
75 
76  if (value.isnull())
77  {
78  // remove a subtree
79  if (root)
80  {
81  UniConfValueTree *node = root->find(key);
82  if (node)
83  {
84  hold_delta();
85  // Issue notifications for every key that gets deleted.
86  node->visit(wv::bind(&UniTempGen::notify_deleted, this,
87  _1, _2),
88  NULL, false, true);
89  delete node;
90  if (node == root)
91  root = NULL;
92  dirty = true;
93  unhold_delta();
94  }
95  }
96  }
97  else if (!trailing_slash)
98  {
99  UniConfValueTree *node = root;
100  UniConfValueTree *prev = NULL;
101  UniConfKey prevkey;
102 
103  UniConfKey::Iter it(key);
104  it.rewind();
105  for (;;)
106  {
107  bool more = it.next(); // not the last node in the key?
108 
109  if (!node)
110  {
111  // we'll have to create the sub-node, since we couldn't
112  // find the most recent part of the key.
113  node = new UniConfValueTree(prev, prevkey,
114  more ? WvString::empty : value);
115  dirty = true;
116  if (!prev) // we just created the root
117  root = node;
118  if (more)
119  delta(node->fullkey(), WvString::empty); // AUTO-VIVIFIED
120  else
121  {
122  delta(node->fullkey(), value); // ADDED
123  break; // done!
124  }
125  }
126  else if (!more)
127  {
128  // don't have to create the most recent sub-node, but there
129  // are no more sub-nodes; that means we're changing the value
130  // of an existing node.
131  if (value != node->value())
132  {
133  node->setvalue(value);
134  dirty = true;
135  delta(node->fullkey(), value); // CHANGED
136  }
137  break;
138  }
139  prevkey = *it;
140  prev = node;
141  node = prev->findchild(prevkey);
142  }
143  assert(node);
144  }
145 
146  unhold_delta();
147 }
148 
149 
150 void UniTempGen::setv(const UniConfPairList &pairs)
151 {
152  setv_naive(pairs);
153 }
154 
155 
157 {
158  if (root)
159  {
160  UniConfValueTree *node = root->find(key);
161  return node != NULL && node->haschildren();
162  }
163  return false;
164 }
165 
166 
168 {
169  if (root)
170  {
171  UniConfValueTree *node = root->find(key);
172  if (node)
173  {
174  ListIter *it = new ListIter(this);
175  UniConfValueTree::Iter i(*node);
176  for (i.rewind(); i.next(); )
177  it->add(i->key(), i->value());
178  return it;
179  }
180  }
181  return NULL;
182 }
183 
184 
186 {
188 }
189 
190 
192 {
193  return UniConfGen::refresh();
194 }