2 * Worldvisions Weaver Software:
3 * Copyright (C) 2002 Net Integration Technologies, Inc.
5 * A UniConf hierarchical key path abstraction.
9 #include "uniconfkey.h"
15 unsigned WvHash(const UniConfKey
&k
)
17 int numsegs
= k
.right
- k
.left
;
25 result
= WvHash(k
.store
->segments
[k
.left
]);
28 result
= WvHash(k
.store
->segments
[k
.left
])
29 ^ WvHash(k
.store
->segments
[k
.right
- 1])
36 // The initial value of 1 for the ref_count of these guarantees
37 // that they won't ever be deleted
38 UniConfKey::Store
UniConfKey::EMPTY_store(1, 1);
39 UniConfKey::Store
UniConfKey::ANY_store(1, 1, "*");
40 UniConfKey::Store
UniConfKey::RECURSIVE_ANY_store(1, 1, "...");
42 UniConfKey
UniConfKey::EMPTY(&EMPTY_store
, 0, 0);
43 UniConfKey
UniConfKey::ANY(&ANY_store
, 0, 1);
44 UniConfKey
UniConfKey::RECURSIVE_ANY(&RECURSIVE_ANY_store
, 0, 1);
47 UniConfKey::Store::Store(int size
, int _ref_count
,
56 parts
.split(key
, "/");
58 segments
.resize(parts
.count());
59 WvStringList::Iter
part(parts
);
60 for (part
.rewind(); part
.next(); )
64 segments
.append(*part
);
66 if (!!key
&& key
[key
.len()-1] == '/' && segments
.used() > 0)
67 segments
.append(Segment());
71 UniConfKey
&UniConfKey::collapse()
73 if ((right
- left
== 1 && !store
->segments
[right
-1])
76 if (--store
->ref_count
== 0)
86 void UniConfKey::unique()
88 if (store
->ref_count
== 1)
91 Store
*old_store
= store
;
92 store
= new Store(right
- left
, 1);
93 for (int i
=left
; i
<right
; ++i
)
94 store
->segments
.append(old_store
->segments
[i
]);
99 UniConfKey::UniConfKey(const UniConfKey
&_path
, const UniConfKey
&_key
) :
100 store(new Store(_path
.numsegments() + _key
.numsegments() + 1, 1)),
104 bool hastrailingslash
= _key
.isempty() || _key
.hastrailingslash();
105 for (int i
=_path
.left
; i
<_path
.right
; ++i
)
107 const Segment
&segment
= _path
.store
->segments
[i
];
110 store
->segments
.append(segment
);
113 for (int j
=_key
.left
; j
<_key
.right
; ++j
)
115 const Segment
&segment
= _key
.store
->segments
[j
];
118 store
->segments
.append(segment
);
121 if (hastrailingslash
)
123 store
->segments
.append("");
130 void UniConfKey::append(const UniConfKey
&_key
)
132 bool hastrailingslash
= _key
.isempty() || _key
.hastrailingslash();
134 store
->segments
.resize(right
- left
+ _key
.right
- _key
.left
+ 1);
135 for (int j
=_key
.left
; j
<_key
.right
; ++j
)
137 const Segment
&segment
= _key
.store
->segments
[j
];
140 store
->segments
.replace(right
, segment
);
143 if (hastrailingslash
)
145 store
->segments
.replace(right
, "");
152 void UniConfKey::prepend(const UniConfKey
&_key
)
156 for (int j
=_key
.left
; j
<_key
.right
; ++j
)
158 if (!!_key
.store
->segments
[j
])
161 store
->segments
.resize(shift
+ right
- left
, shift
);
162 for (int j
=_key
.left
; j
<_key
.right
; ++j
)
164 const Segment
&segment
= _key
.store
->segments
[j
];
167 store
->segments
.replace(left
+ j
- _key
.left
, segment
);
174 bool UniConfKey::iswild() const
176 for (int i
=left
; i
<right
; ++i
)
177 if (store
->segments
[i
].iswild())
183 UniConfKey
UniConfKey::pop(int n
)
188 if (n
> right
- left
)
194 UniConfKey
result(store
, old_left
, left
);
196 return result
.collapse();
200 UniConfKey
UniConfKey::range(int i
, int j
) const
202 if (j
> right
- left
)
208 return UniConfKey(store
, left
+ i
, left
+ j
).collapse();
212 WvString
UniConfKey::printable() const
214 switch (right
- left
)
217 return WvString::empty
;
219 return store
->segments
[left
];
223 for (int i
=left
; i
<right
; ++i
)
225 buf
.putstr(store
->segments
[i
]);
235 int UniConfKey::compareto(const UniConfKey
&other
) const
238 for (i
=left
, j
=other
.left
; i
<right
&& j
<other
.right
; ++i
, ++j
)
240 int val
= strcasecmp(store
->segments
[i
], other
.store
->segments
[j
]);
246 if (j
== other
.right
)
256 bool UniConfKey::matches(const UniConfKey
&pattern
) const
258 // TODO: optimize this function
259 if (*this == pattern
)
262 UniConfKey
head(pattern
.first());
265 if (head
== UniConfKey::ANY
)
269 return removefirst().matches(pattern
.removefirst());
272 // handle ... wildcard
273 if (head
== UniConfKey::RECURSIVE_ANY
)
275 UniConfKey
tail(pattern
.removefirst());
277 return true; // recursively matches anything
278 for (int n
= 0; ; ++n
)
280 UniConfKey
part(removefirst(n
));
281 if (part
.matches(tail
))
289 // no other wildcard arrangements currently supported
294 bool UniConfKey::suborsame(const UniConfKey
&key
) const
296 int n
= numsegments();
297 if (hastrailingslash())
300 if (key
.first(n
) == first(n
))
306 bool UniConfKey::suborsame(const UniConfKey
&key
, UniConfKey
&subkey
) const
308 int n
= numsegments();
310 // Compensate for the directory-style naming convention of the
312 if (hastrailingslash())
315 if (key
.first(n
) == first(n
))
317 subkey
= key
.removefirst(n
);
324 UniConfKey
UniConfKey::subkey(const UniConfKey
&key
) const
327 wvassert(suborsame(key
, answer
),
328 "this = '%s'\nkey = '%s'", printable(), key
);